线程池中的一些细节

线程池的工作原理

我认为线程池它就是一个调度任务的工具。

众所周知在初始化线程池会给定线程池的大小,假设现在我们有 1000 个线程任务需要运行,而线程池的大小为 10,20 个线程来调度这1000个任务。

而这里的 10~20 个线程最后会由线程池封装为 ThreadPoolExecutor.Worker 对象,而这个 Worker 是实现了 Runnable 接口的,所以他自己本身就是一个线程。

深入分析

ExecutorService executorService =  new ThreadPoolExecutor(2,2,0L,TimeUnit.SECONDS,
            new LinkedBlockingQueue<Runnable>(2));

这里我们来做一个模拟,创建了一个核心线程、最大线程数、阻塞队列都为2的线程池。

这里假设线程池已经完成了预热,也就是线程池内部已经创建好了两个线程 Worker

当我们往一个线程池丢一个任务会发生什么事呢?

  • 第一步是生产者,也就是任务提供者他执行了一个 execute() 方法,本质上就是往这个内部队列里放了一个任务。
  • 之前已经创建好了的 Worker 线程会执行一个 while 循环 ---> 不停的从这个内部队列里获取任务。(这一步是竞争的关系,都会抢着从队列里获取任务,由这个队列内部实现了线程安全。)
  • 获取得到一个任务后,其实也就是拿到了一个 Runnable 对象(也就是 execute(Runnable task) 这里所提交的任务),接着执行这个 Runnable 的 run() 方法,而不是 start(),这点需要注意后文分析原因。

为什是 run() 而不是 start()

为什么线程池在调度的时候执行的是 Runnable 的 run() 方法,而不是 start() 方法呢?

网上大牛讲的都是只有执行了 start() 方法后操作系统才会给我们创建一个独立的线程来运行,而 run() 方法只是一个普通的方法调用。

而在线程池这个场景中却恰好就是要利用它只是一个普通方法调用。

假设这里是调用的 Runnable 的 start 方法,那会发生什么事情。

如果我们往一个核心、最大线程数为 2 的线程池里丢了 1000 个任务,那么它会额外的创建 1000 个线程,同时每个任务都是异步执行的,一下子就执行完毕了

从而没法做到由这两个 Worker 线程来调度这 1000 个任务,而只有当做一个同步阻塞的 run() 方法调用时才能满足这个要求。

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章