本文主要介绍了Java自定义参数创建线程池的示例,其中也使用了java的并发工具类CountDownLatch和CyclicBarrier(顺便练习一下他们的用法),记录第一次发博客
使用线程池的好处
- 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
- 提高响应速度。当任务到达时,任务可以不需要的等到线程创建就能立即执行。
- 提高线程的可管理性。线程是稀缺资源,如果无限制的创建,不仅会消耗系统资源,还会降低系统的稳定性,使用线程池可以进行统一的分配,调优和监控。
通过Executors工具类创建的线程池的弊端
FixedThreadPool
和SingleThreadExecutor
使用无界队列LinkedBlockingQueue
(队列的容量为 Intger.MAX_VALUE)作为线程池的工作队列,可能堆积大量的请求,从而导致 OOM。- ScheduledThreadPoolExecutor使用无界队列DelayQueue(队列的容量为 Intger.MAX_VALUE)作为线程池的工作队列,可能堆积大量的请求,从而导致 OOM。
CachedThreadPool
允许创建的线程数量为 Integer.MAX_VALUE ,可能会创建大量线程,从而导致 OOM。
自定义参数创建线程池示例
package thread; import java.util.concurrent.*; public class ThreadPoolDemo { //线程池的核心线程数量 private static final int CORE_POOL_SIZE = 5; //线程池的最大线程数 private static final int MAX_POOL_SIZE = 10; //阻塞队列的容量 private static final int QUEUE_CAPACITY = 100; //当线程数大于核心线程数时,多余的空闲线程存活的最长时间 private static final Long KEEP_ALIVE_TIME = 1L; public static int threadNum = 5; public static void main(String[] args) throws InterruptedException { CountDownLatch countDownLatch = new CountDownLatch(threadNum); CyclicBarrier cyclicBarrier = new CyclicBarrier(threadNum); //使用阿里巴巴推荐的创建线程池的方式 //通过ThreadPoolExecutor构造函数自定义参数创建 ThreadPoolExecutor executor = new ThreadPoolExecutor( CORE_POOL_SIZE, MAX_POOL_SIZE, KEEP_ALIVE_TIME, TimeUnit.SECONDS, new ArrayBlockingQueue<>(QUEUE_CAPACITY), //线程池达到饱和之后的拒绝策略, // 调用执行自己的线程运行任务,也就是直接在调用execute方法的线程中运行被拒绝的任务 new ThreadPoolExecutor.CallerRunsPolicy()); for (int i = 0; i < threadNum; i++) { //简洁的Lambda表达式 executor.execute(() -> { try { //当前线程阻塞,直到所有线程都准备就绪 cyclicBarrier.await(); System.out.println( "当前线程: "+ Thread.currentThread().getName() + " 开始工作啦"); //模拟业务代码 Thread.sleep(1000); System.out.println( "当前线程: "+ Thread.currentThread().getName() + " 结束工作啦"); } catch (InterruptedException e) { e.printStackTrace(); } catch (BrokenBarrierException e) { e.printStackTrace(); } countDownLatch.countDown(); }); } //主线程等待工作线程全部结束 countDownLatch.await(); //关闭线程池 executor.shutdown(); System.out.println("全部线程工作完成"); } }