并发队列
队列:先进先出,后进后出。
非阻塞队列
阻塞队列(BlockingQueue)
- ArrayBlockingQueue (java.util.concurrent)
- DelayedWorkQueue in ScheduledThreadPoolExecutor (java.util.concurrent)
- BlockingDeque (java.util.concurrent)
- SynchronousQueue (java.util.concurrent)
- DelayQueue (java.util.concurrent)
- TransferQueue (java.util.concurrent)
- LinkedBlockingQueue (java.util.concurrent)
- PriorityBlockingQueue (java.util.concurrent)
阻塞式队列入列的时候,如果超出队列总数,会进行等待。出列的时候队列为空的情况下,也会进行等待
public static void main(String[] args) {
BlockingQueue<String> blockingQueue = new ArrayBlockingQueue<String>(2);
System.out.println(blockingQueue.offer("1"));
System.out.println(blockingQueue.offer("1"));
System.out.println(blockingQueue.offer("1"));//false,因为超出队列长度
try {
System.out.println(blockingQueue.offer("1",3, TimeUnit.SECONDS));//如果三秒后还该队列中的元素没有被拿出至小于2则返回false
} catch (InterruptedException e) {
e.printStackTrace();
}
}
阻塞和非阻塞队列的区别
- 阻塞式队列入列的时候,如果超出队列总数,会进行等待。出列的时候队列为空的情况下,也会进行等待。
- 阻塞队列最大好处是能够防止队列溢出,防止丢失数据。
- 非阻塞队列性能相对更好。
线程池
目的
- 降低资源消耗。通过重复利用已创建的线程降低线程创建和销毁造成的消耗。
- 提高响应速度。当任务到达时,任务可以不需要等到线程创建就能立即执行。
- 提高线程的可管理性。线程是稀缺资源,如果无限制地创建,不仅会消耗系统资源还会降低系统的稳定性,使用线程池可以进行统一分配、调优和监控。但是,要做到合理利用。
创建方式线程池的方式
核心是通过Executor接口,它的最顶层实现是ThreadPoolExecutor类,Executors工厂类中提供的newScheduledThreadPool、newFixedThreadPool、newCachedThreadPool方法其实也只是ThreadPoolExecutor的构造函数参数不同而已。通过传入不同的参数,就可以构造出适用于不同应用场景下的线程池,那么它的底层原理是怎样实现的呢,这篇就来介绍下ThreadPoolExecutor线程池的运行过程。
Executors
- newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
- newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
- newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
- newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
public static void main(String[] args) {
ExecutorService executorService = Executors.newCachedThreadPool();
ExecutorService executorService1 = Executors.newFixedThreadPool(3);
ScheduledExecutorService scheduledExecutorService = Executors.newScheduledThreadPool(3);
ExecutorService executorService2 = Executors.newSingleThreadExecutor();
});
}
并不推荐使用这几种方式创建,因为都有可能引发异常。 推荐使用ThreadPoolExecutor自己创建
ThreadPoolExedcutor
使用改类可以自定义满足自己需求的线程池
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
corePoolSize: 核心线程数
maximumPoolSize: 最大线程数
keepAliveTime:超过核心线程数的线程,不执行任务后多长时间会销毁
BlockingQueue: 阻塞队列,当执行的任务数大于最大线程数,多余的会在阻塞队列中等待。