多线程进阶-JUC

63 阅读3分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第13天

1.线程池(重要)

线程池:三大方法,7大参数,4种拒绝策略

池化技术

程序的运行,本质:占用系统的资源! 优化资源的使用!=> 池化技术

线程池、连接池、内存池、对象池....... 创建、销毁、都十分浪费资源

池化技术:事先准备好一些资源,有人要用,就来我这里拿,用完之后还給我。

线程池的好处:

  1. 降低资源的消耗
  2. 提高响应的速度
  3. 方便管理

线程复用,可以控制最大并发数,管理线程

线程池:三大方法

  • ExecutorService threadPool = Executors.newSingleThreadExecutor();//单个线程
  • ExecutorService threadPool2 = Executors.newFixedThreadPool(5); //创建一个固定的线程池的大小
  • ExecutorService threadPool3 = Executors.newCachedThreadPool(); //可伸缩的
 //Exectors 工具类 , 3大方法
 public class Demo1 {
     public static void main(String[] args) {
        // ExecutorService threadPool = Executors.newSingleThreadExecutor();//单个线程
         //ExecutorService threadPool = Executors.newFixedThreadPool(5);//创建一个固定的线程池大小
         ExecutorService threadPool = Executors.newCachedThreadPool();//  可伸缩的,遇强则强,遇弱则弱
 ​
         try {
             for (int i = 0; i < 100; i++) {
                 threadPool.execute(()->{
                     System.out.println(Thread.currentThread().getName()+"  ok ");
                 });
             }
         } catch (Exception e) {
             e.printStackTrace();
         } finally {
             threadPool.shutdown();
         }
     }
 }
 ​

7大参数

  • int corePoolSize, //核心线程池大小
  • int maximumPoolSize, //最大的线程池大小
  • long keepAliveTime, //超时了没有人调用就会释放
  • TimeUnit unit, //超时单位
  • BlockingQueue workQueue, //阻塞队列
  • ThreadFactory threadFactory, //线程工厂 创建线程的 一般不用动
  • RejectedExecutionHandler handler //拒绝策略

源码分析

本质:ThreadPoolExector()

 public static ExecutorService newSingleThreadExecutor() {
     return new FinalizableDelegatedExecutorService
         (new ThreadPoolExecutor(1, 1,
                                 0L, TimeUnit.MILLISECONDS,
                                 new LinkedBlockingQueue<Runnable>()));
 }
 public static ExecutorService newFixedThreadPool(int nThreads) {
     return new ThreadPoolExecutor(nThreads, nThreads,
                                   0L, TimeUnit.MILLISECONDS,
                                   new LinkedBlockingQueue<Runnable>());
 }
 public static ExecutorService newCachedThreadPool() {
     return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                   60L, TimeUnit.SECONDS,
                                   new SynchronousQueue<Runnable>());
 }
 ​
 ​
 ​
 public ThreadPoolExecutor(int corePoolSize,  //核心线程池大小
                           int maximumPoolSize, //最大的线程池大小
                           long keepAliveTime,  //超时了没有人调用就会释放
                           TimeUnit unit, //超时单位
                           BlockingQueue<Runnable> workQueue, //阻塞队列
                           ThreadFactory threadFactory, //线程工厂 创建线程的 一般不用动
                           RejectedExecutionHandler handler //拒绝策略
                          ) {
     if (corePoolSize < 0 ||
         maximumPoolSize <= 0 ||
         maximumPoolSize < corePoolSize ||
         keepAliveTime < 0)
         throw new IllegalArgumentException();
     if (workQueue == null || threadFactory == null || handler == null)
         throw new NullPointerException();
     this.corePoolSize = corePoolSize;
     this.maximumPoolSize = maximumPoolSize;
     this.workQueue = workQueue;
     this.keepAliveTime = unit.toNanos(keepAliveTime);
     this.threadFactory = threadFactory;
     this.handler = handler;
 }
 ​

image-20221009150001316

重点:

阿里巴巴的Java操作手册中明确说明:对于Integer.MAX_VALUE初始值较大,所以一般情况我们要使用底层的ThreadPoolExecutor来创建线程池。

image-20221009150654596

手动创建一个线程池

自定义线程池! 工作工作中要用到的

最大承载:Deque + max (队列容量大小+maxPoolSize)

 //Exectors 工具类 , 3大方法
 public class Demo1 {
     public static void main(String[] args) {
         //自定义线程池! 工作工作中要用到的
       ExecutorService threadPool = new ThreadPoolExecutor(2,
               5,
               3,
               TimeUnit.SECONDS,
               new LinkedBlockingDeque<>(3),
               Executors.defaultThreadFactory(),
               new ThreadPoolExecutor.DiscardOldestPolicy()
               );
 ​
         try {
             for (int i = 0; i < 10; i++) {
                 threadPool.execute(()->{
                     System.out.println(Thread.currentThread().getName()+"  ok ");
                 });
             }
         } catch (Exception e) {
             e.printStackTrace();
         } finally {
             threadPool.shutdown();
         }
     }
 }
 ​

4种拒绝策略

image-20221009151712667

(1)new ThreadPoolExecutor.AbortPolicy(): //该拒绝策略为:银行满了,还有人进来,不处理这个人的,并抛出异常

超出最大承载,就会抛出异常:

(2)new ThreadPoolExecutor.CallerRunsPolicy(): //该拒绝策略为:哪来的去哪里 main线程进行处理

(3)new ThreadPoolExecutor.DiscardPolicy(): //该拒绝策略为:队列满了,丢掉异常,不会抛出异常。

(4)new ThreadPoolExecutor.DiscardOldestPolicy(): //该拒绝策略为:队列满了,尝试去和最早的进程竞争,不会抛出异常

小结和拓展

如何去设置线程池的最大大小如何去设置?

CPU密集型和IO密集型!(调优)

1、CPU密集型:电脑的核数是几核就选择几;选择maximunPoolSize的大小

  ExecutorService threadPool = new ThreadPoolExecutor(
               2,
               Runtime.getRuntime().availableProcessors(),
               3,
               TimeUnit.SECONDS,
               new LinkedBlockingDeque<>(3),
               Executors.defaultThreadFactory(),
               new ThreadPoolExecutor.DiscardOldestPolicy()
               );

2、I/O密集型:

在程序中有15个大型任务,io十分占用资源;I/O密集型就是判断我们程序中十分耗I/O的线程数量,大约是最大I/O数的一倍到两倍之间。