共计 2132 个字符,预计需要花费 6 分钟才能阅读完成。
线程池概念
咱们上篇文章剖析了 ThreadPoolExecutor,如果要用一句话阐明它的次要劣势,就是线程置换。还有 Executors 工具类,极大的简化了研发人员工作。
我用一个图反复形容下线程池概念。多生产 - 多生产模型。
- 生产者将线程工作丢进线程池中,生产者就就完结了。
- 线程池管制消费者生产元素,消费者能够是 1 个或者多个,取决于线程池参数 corePoolSize 和 maxPoolSize 设置。
- 阻塞队列是用来装生产者丢进去的线程工作,如 ArrayBlockingQueue,LinkedBlockingQueue,DelayedQueue 等。如果生产者生产能力超过消费者生产能力,如果阻塞队列有长度限度并且超过队列长度线程池会执行饱和策略,如果队列没有长度限度,可也能呈现 OOM 哦,因为线程工作可能把内存都撑爆了,这也是面试常考点哦!
具体概念能够翻看我上一篇文章《线程池面试必考问题》。
定时工作延时原理
还记得咱们下面说的阻塞队列吗?定时工作线程池底层应用 DelayedQueue 实现的,这种提早队列有一个最大的特点:按时出队列,大家都考过驾照吧,科目三考试的时候都是车上坐的是 4 集体,假如一个人考试须要花 15 分钟,那么考试学员队列看起来是这样的。
DelayedQueue 底层须要实现 Delayed 接口同时须要实现 getDelay 办法和 compareTo 办法,getDelay 办法用于计算出队列工夫,一旦小于 0 就会出队列;compareTo 办法用于按触发工夫从小到大排序。这就是 Schedule 线程池工作延时原理,如果须要看案例代码,请参考我文章《并发队列:PriorityBlockingQueue 和 DelayQueue 案例应用》。
scheduleWithFixedDelay 和 scheduleAtFixedRate 区别
由上图可知:假如线程工作:耗时 1 秒,定时 3 秒执行,scheduleWithFixedDelay 其实是 4 秒执行一次。
- scheduleWithFixedDelay:是以工作完结工夫周期运行。
- scheduleAtFixedRate:是以固定周期运行。
FutureTask 获取返回值
在 ScheduledThreadPoolExecutor 中,ScheduledFutureTask 是获取定时工作返回值,继承 FutureTask。咱们看下 FutureTask 调用 get 阻塞简化流程图。
- 向线程池增加工作,工作被封装成 ScheduledFutureTask 并且实现 Callable 接口是为了获取工作返回值。
- 当客户端线程通过 get 形式获取线程池线程执行的返回值,客户端线程会阻塞直到线程池线程工作执行完。
在理论使用,咱们个别拿返回值测试多线程性能。
Timer 比拟
- Timer 是单线程,而且不带返回值。ScheduledThreadPoolExecutor 是多线程的,采纳线程复用代替创立新的线程,并且 FutureTask 带返回值。
- Timer 线程调用 sche 办法,如果 TimerTask 出异样,Timer 单线程间接挂掉退出,而 ScheduledThreadPoolExecutor 会捕捉了异样,不影响其余消费者线程。上面是代码测试。
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.TimeUnit;
/**
* @author:jiaolian
* @date:Created in 2021-02-25 13:50
* @description:Timer 工作异样,Timer 线程退出!* @modified By:* 公众号: 叫练 */public class TimerTaskExceptionTest {public static void main(String[] args) throws InterruptedException {Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {System.out.println("first task");
}
},0,1000);
TimeUnit.SECONDS.sleep(3);
timer.schedule(new TimerTask() {
@Override
public void run() {System.out.println("second task");
int x = 5/0;
}
},0,1000);
}
}
如上代码:timer 提交了 first_task 和 second_task 两个工作,3 秒后,second_task 执行 5 / 0 会抛出异样,此时 timer 线程会退出。如果换成 ScheduledThreadPoolExecutor 则不会影响 first_task。在理论利用中,举荐用定时工作线程池中的办法去解决工作。
总结
明天咱们介绍了线程池中面试中几个重要的面试点,整理出来心愿能对你有帮忙,写的比不全,同时还有许多须要修改的中央,心愿亲们加以斧正和点评,喜爱的请点赞加关注哦。点关注,不迷路,我是 叫练【公众号】,微信号 【jiaolian123abc】 边叫边练。