本文主要介绍了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("全部线程工作完成");
}
}