乐趣区

关于后端:线程池的简单实现Java线程池初学者必读指南

“ 作为一名 Java 开发者,是否已经遇到过多线程并发的问题?线程数量过多时,会导致资源节约,利用性能降落,甚至产生线程死锁的状况。那么,有没有一种办法能够无效地治理线程,防止这些问题呢?答案是必定的,那就是线程池。在本文中,咱们将通过 Java 的角度,探讨线程池的奥秘,深刻理解线程池的劣势,学习如何应用线程池实现多线程并发。”

线程池是如何创立的?

JAVA 中创立线程池次要有两类办法,一类是 通过 Executors 工厂类提供的办法 ,该类提供了 4 种不同的线程池可供使用。另一类是通过ThreadPoolExecutor 类 进行自定义创立。

Executors 工厂类


// 五种线程池://     ExecutorService threadPool = null;
//     threadPool = Executors.newCachedThreadPool();// 有缓冲的线程池,线程数 JVM 管制
//     threadPool = Executors.newFixedThreadPool(3);// 固定大小的线程池
//     threadPool = Executors.newScheduledThreadPool(2); // 具备延时,定时性能
//     threadPool = Executors.newSingleThreadExecutor();// 单线程的线程池,只有一个线程在工作
//     threadPool = new ThreadPoolExecutor();// 默认线程池,可控制参数比拟多   

private static void createCachedThreadPool() {ExecutorService executorService = Executors.newCachedThreadPool();
        for (int i = 0; i < 10; i++) {
            final int index = i;
            executorService.execute(() -> {
                // 获取线程名称, 默认格局:pool-1-thread-1
                System.out.println(DateUtil.now() + "" + Thread.currentThread().getName() +" " + index);
                // 期待 2 秒
                sleep(2000);
            });
        }
    }

ThreadPoolExecutor 类

ThreadPoolExecutor 提供构造方法,须要本人设置具体的参数,更加灵便

public ThreadPoolExecutor(int corePoolSize, // 外围线程数
                              int maximumPoolSize, // 最大工作线程
                              long keepAliveTime, // 存活工夫,线程没有工作执行时最多放弃多久工夫会终止。TimeUnit unit, // 工夫单位
                              BlockingQueue<Runnable> workQueue, // 工作队列
                              ThreadFactory threadFactory, // 线程工厂,次要用来创立线程,默及失常优先级、非守护线程。RejectedExecutionHandler handler // 回绝策略,当创立新线程使线程数大于最大线程的状况下,会执行
                              ) {// 省略...}

线程池的主要参数

  • corePoolSize 外围线程数
    外围线程数,线程池中始终存活的线程数。
  • BlockingQueue 工作队列
    workQueue = new ArrayBlockingQueue<>(5);// 基于数组的先进先出队列,有界
    workQueue = new LinkedBlockingQueue<>();// 基于链表的先进先出队列,无界
    workQueue = new SynchronousQueue<>();// 无缓冲的期待队列,无界
  • threadFactory 线程工厂
    用于设置创立线程的工厂,能够通过线程工厂给每个创立进去的。线程设置更有意义的名字。应用开源框架 guava 提供的 ThreadFactoryBuilder 能够疾速给线程池里的线程设置有意义的名字,代码如下:

    new ThreadFactoryBuilder().setNameFormat("XX-task-%d").build();
  • handler
    回绝策略,回绝解决工作时的策略,4 种可选,默认为 AbortPolicy。
参数 形容
AbortPolicy 回绝并抛出异样
CallerRunsPolicy 只用调用者所在线程来运行工作
DiscardOldestPolicy 摈弃队列头部(最旧)的一个工作,并执行当前任务。
DiscardPolicy 摈弃当前任务。
 RejectedExecutionHandler rejected = null;
    rejected = new ThreadPoolExecutor.AbortPolicy();// 默认,队列满了丢工作抛出异样
    rejected = new ThreadPoolExecutor.DiscardPolicy();// 队列满了丢工作不异样
    rejected = new ThreadPoolExecutor.DiscardOldestPolicy();// 将最早进入队列的工作删,之后再尝试退出队列
    rejected = new ThreadPoolExecutor.CallerRunsPolicy();// 如果增加到线程池失败,那么主线程会本人去执行

线程池的执行过程?

  1. 主线程提交工作到线程池,如果以后线程数小于外围线程数,创立新的线程用于执行工作,如果不是,下一步。
  2. 此时外围线程已满,再判断工作队列寄存的线程数是否满了,如果没有满,则放入工作队列,如果不是,下一步。
  3. 此时工作队列满了,再看以后线程数是否等于最大线程数,如果是的话,执行回绝策略,如果不是,创立新的线程,执行工作。

配置线程池最大线程数

  • cpu 密集型 maximumPoolSize = n*cpu + 1
  • io 密集型 maximumPoolSize = 2 * n * cpu

线程池的敞开

能够通过调用线程池的 shutdownshutdownNow 办法来敞开线程池。
相同点:遍历所有的工作线程,而后 interrupt 掉线程
不同点:shutdown 调用后,不再承受新的工作,然而会期待正在运行的线程,进行没有执行工作的线程
shutdownNow 调用后 会尝试进行正在运行或暂停工作的线程

原创不易,麻烦点个赞​再走呗!

本文由 mdnice 多平台公布

退出移动版