一、线程池的创建和常用参数分析
先看一个线程池的创建
private static void testThreadPool(){
ExecutorService executorService = Executors.newFixedThreadPool(1);
Future<?> future = executorService.submit(() -> {
System.out.println(Thread.currentThread().getName() + " running");
});
}
翻看newFixedThreadPool()的源码可以看到最终执行的时候有以下几个参数:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
...
}
a) corePoolSize 核心线程数,保持在线程池中线程的数量
b) maxinumPoolSize 线程池允许的最大线程数
c) keepAliveTime/timeUnit 线程池中线程空闲不被释放的最大时间,配合timeUnit使用,为0表示永远不被释放。
d) workQuene 线程任务阻塞队列
e) threadFactory 线程池创建工厂
f) handler(RejectedExecutionHandler) 当workQuene无法存放新任务的时候,或添加新任务后线程池停止工作,使用设置的拒绝策略拒绝添加新任务的执行,可以用rejectedExecution来实心自己的拒绝策略。默认拒绝策略:AbortPolicy,直接抛出异常。
二、常用线程池和执行过程
Java中提供的常用线程池有:
1)固定线程数量的线程池
ExecutorService executorService = Executors.newFixedThreadPool(1);
固定数量的线程。
2)单线程的线程池
ExecutorService executorServiceSingle = Executors.newSingleThreadExecutor();
单例的线程。
3)可缓存的线程池
ExecutorService executorServiceCache = Executors.newCachedThreadPool();
核心线程数为0,最大线程数无限大(实际为int最大;空闲线程可以缓存60秒,空闲超过60s的线程会被回收;使用了SynchronousQueue同步队列,添加任务的同时须有工作线程来取任务才完成任务的添加和执行。
4)定时执行的线程池
ExecutorService executorServiceTime = Executors.newScheduledThreadPool(1);
执行过程
submit()和execute()都是 ExecutorService 的方法,是添加线程到线程池中,execute()没有返回值。
submit()有返回值,返回future,1)可以执行cancle方法取消执行 。2)可以通过get()方法判断是否执行状态。
三、线程池常用队列LinkedBlockingQueue
原理部分不再详述。使用参考文档LinkedBlockingQueue使用
三、可定时执行的线程池
ScheduledExecutorService 他的原理是线程池工作线程+时间任务队列。
ScheduledExecutorService在设计之初就是为了解决Timer&TimerTask的单线程问题。因为天生就是基于多线程机制,所以任务之间不会相互影响(只要线程数足够。当线程数不足时,有些任务会复用同一个线程)。
除此之外,因为其内部使用的延迟队列,本身就是基于等待/唤醒机制实现的,所以CPU并不会一直繁忙。同时,多线程带来的CPU资源复用也能极大地提升性能。
它支持四个方法:
/**
* 带延迟时间的调度,只执行一次
* 调度之后可通过Future.get()阻塞直至任务执行完毕
*/
1. public ScheduledFuture<?> schedule(Runnable command,
long delay, TimeUnit unit);
/**
* 带延迟时间的调度,只执行一次
* 调度之后可通过Future.get()阻塞直至任务执行完毕,并且可以获取执行结果
*/
2. public <V> ScheduledFuture<V> schedule(Callable<V> callable,
long delay, TimeUnit unit);
/**
* 带延迟时间的调度,循环执行,固定频率
*/
3. public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,
long initialDelay,
long period,
TimeUnit unit);
/**
* 带延迟时间的调度,循环执行,固定延迟
*/
4. public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
long initialDelay,
long delay,
TimeUnit unit);
1、schedule Runnable
该方法用于带延迟时间的调度,只执行一次。调度之后可通过Future.get()阻塞直至任务执行完毕。我们来看一个例子。
@Test public void test_schedule4Runnable() throws Exception {
ScheduledExecutorService service = Executors.newSingleThreadScheduledExecutor();
ScheduledFuture future = service.schedule(() -> {
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("task finish time: " + format(System.currentTimeMillis()));
}, 1000, TimeUnit.MILLISECONDS);
System.out.println("schedule finish time: " + format(System.currentTimeMillis()));
System.out.println("Runnable future's result is: " + future.get() +
", and time is: " + format(System.currentTimeMillis()));
}
上述代码达到的效果应该是这样的:延迟执行时间为1秒,任务执行3秒,任务只执行一次,同时通过Future.get()阻塞直至任务执行完毕。
2、schedule Callable
和Runnable基本相同,唯一的区别在于future.get()能拿到Callable返回的真实结果。
3、scheduleAtFixedRate
该方法用于固定频率地对一个任务循环执行,我们通过一个例子来看看效果。
@Test public void test_scheduleAtFixedRate() {
ScheduledExecutorService service = Executors.newScheduledThreadPool(5);
service.scheduleAtFixedRate(() -> {
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("task finish time: " + format(System.currentTimeMillis()));
}, 1000L, 1000L, TimeUnit.MILLISECONDS);
System.out.println("schedule finish time: " + format(System.currentTimeMillis()));
while (true) {
}
}
4、scheduleWithFixedDelay
@Test public void test_scheduleWithFixedDelay() {
ScheduledExecutorService service = Executors.newScheduledThreadPool(5);
service.scheduleWithFixedDelay(() -> {
try {
Thread.sleep(3000L);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("task finish time: " + format(System.currentTimeMillis()));
}, 1000L, 1000L, TimeUnit.MILLISECONDS);
System.out.println("schedule finish time: " + format(System.currentTimeMillis()));
while (true) {
}
}
直白地讲,scheduleAtFixedRate()为固定频率,scheduleWithFixedDelay()为固定延迟。固定频率是相对于任务执行的开始时间,而固定延迟是相对于任务执行的结束时间,这就是他们最根本的区别!
最后给出一个案例,使用future获取异步结果的用法
来源:CSDN
作者:Mr.sleepy
链接:https://blog.csdn.net/weixin_44726656/article/details/104550192