乐趣区

关于线程池:图解定时任务线程池

线程池概念


咱们上篇文章剖析了 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 阻塞简化流程图。

  1. 向线程池增加工作,工作被封装成 ScheduledFutureTask 并且实现 Callable 接口是为了获取工作返回值。
  2. 当客户端线程通过 get 形式获取线程池线程执行的返回值,客户端线程会阻塞直到线程池线程工作执行完。

在理论使用,咱们个别拿返回值测试多线程性能。

Timer 比拟


  1. Timer 是单线程,而且不带返回值。ScheduledThreadPoolExecutor 是多线程的,采纳线程复用代替创立新的线程,并且 FutureTask 带返回值。
  2. 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】 边叫边练。

退出移动版