1 阻塞队列
1.1 BlockingQueue简介
在多线程环境中,通过队列可以轻松实现数据共享
如在生产者-消费者模型中,通过队列可以很轻松实现二者间的数据共享
常用的有:
ArrayBlockingQueue 由数组组成的有界阻塞队列
LinkedBlockingQueue 由链表组成的有界阻塞队列
PriorityBlockingQueue 支持优先级排序的无界阻塞队列
...
1.2 BlockingQueue常用方法
2 线程池
2.1 线程池概述
线程池是什么:
线程池是一种线程使用模式,线程过多会带来调度开销 进而影响整体性能
而线程池可以维护多个线程 管理待并发执行的任务
这避免了处理短时间任务时创建与销毁线程的代价
为什么使用线程池:
为了减少每次获取资源的消耗,提高对资源的利用率
如线程池,数据库连接池等
使用线程池的好处:
1,降低资源消耗
2,提高响应速度
3,提高线程的可管理性
其工作流程大体为:
在等待队列满之前,线程池中的最多运行的线程数就是corePoolSize,当等待队列满了后,才能创建非核心线程
2.2 ThreadPoolExecutor的参数
/**
* 用给定的初始参数创建一个新的ThreadPoolExecutor。
*/
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler);
构造方法参数的意义:
int corePoolSize: 核心线程数,定义了最少可以同时运行的线程数量
int maximumPoolSize: 当队列中存放的任务到达队列容量时,当前可以同时运行的线程数变为最大线程数
long keepAliveTime: 当线程中的数量大于corePoolSize时,如果没有新任务提交
核心线程外的线程不会立刻销毁,而是会等待,直到等待的时间超过了keepAliveTime才会被回收销毁
TimeUnit unit: 时间单位
BlockingQueue<Runnable> workQueue: 当新任务到达时会先判断当前运行的线程数量是否达到核心线程数
如果达到的话,新任务会被存放到队列中
ThreadFactory threadFactory: executor创建新线程时会用到
RejectedExecutionHandler handler: 饱和策略
自定义线程池:
public static void main(String[] args) throws InterruptedException {
ThreadPoolExecutor threadPool =
new ThreadPoolExecutor(
5,
10,
10,
TimeUnit.SECONDS,
new LinkedBlockingQueue<>(5),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
try {
for (int i = 0; i < 10; i++) {
threadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().currentThread() + " execute");
}
});
}
} catch (Exception e) {
} finally {
threadPool.shutdown();
}
}
2.3 饱和策略
如果当前同时运行的线程数量达到最大线程数,且队列也已经被放满时,可以定义一些策略处理:
ThreadPoolExecutor.AbortPolicy: 抛出RejectedExecutionException异常来拒绝新任务处理
当不指定RejectedExcutionHandler时,作为默认策略
ThreadPoolExecutor.CallerRunsPolicy: 让提交任务的线程直接执行此任务,可能导致数据处理顺序不一致
ThreadPoolExecutor.DiscardPolicy: 不处理新任务,直接丢弃
ThreadPoolExecutor.DiscardOldestPolicy: 丢弃最早的未处理请求