Java并发24 再来一个例子来看看线程池执行过程

线程池执行过程

            • 一 直接上例子
            • 二 饱和策略

一 直接上例子
public class ThreadPoolExecutorTest {

    private static ThreadPoolExecutor pool = new ThreadPoolExecutor(2, 4, 60, TimeUnit.SECONDS, new
            ArrayBlockingQueue<>(10), new ThreadPoolExecutor.AbortPolicy());

    public static void main(String[] args) throws InterruptedException {
        for (int i = 1; i <= 14; i++) {
            Callable<Boolean> task = createTask(i);
            pool.submit(task);
            System.out.println("after task:" + i + " submitted, current active count: "
                    + pool.getActiveCount() + ", size of queue: " + pool.getQueue().size());
        }
        System.out.println("size of queue: " + pool.getQueue().size());
        for (;;){
            TimeUnit.SECONDS.sleep(11);
            System.out.println("size of queue: " + pool.getQueue().size());
            if (0 == pool.getQueue().size())
                break;
        }
        pool.shutdown();
    }

    /**
     * @Author Xu hao
     * @Description 创建任务
     * @Date 2019/3/19 0:08
     * @param i
     * @return java.util.concurrent.Callable
     **/
    private static Callable<Boolean> createTask(int i){

        Callable<Boolean> callable = () -> {
            TimeUnit.SECONDS.sleep(10);
            System.out.println("thread: " + Thread.currentThread().getName() + " execute task: " + i);
            return true;
        };

        return callable;
    }
}

我们在上一篇文章的例子基础上每隔11秒打印一下工作队列的size,
运行结果如下:

after task:1 submitted, current active count: 1, size of queue: 0
after task:2 submitted, current active count: 2, size of queue: 0
after task:3 submitted, current active count: 2, size of queue: 1
after task:4 submitted, current active count: 2, size of queue: 2
after task:5 submitted, current active count: 2, size of queue: 3
after task:6 submitted, current active count: 2, size of queue: 4
after task:7 submitted, current active count: 2, size of queue: 5
after task:8 submitted, current active count: 2, size of queue: 6
after task:9 submitted, current active count: 2, size of queue: 7
after task:10 submitted, current active count: 2, size of queue: 8
after task:11 submitted, current active count: 2, size of queue: 9
after task:12 submitted, current active count: 2, size of queue: 10
after task:13 submitted, current active count: 3, size of queue: 10
after task:14 submitted, current active count: 4, size of queue: 10
size of queue: 10
thread: pool-1-thread-1 execute task: 1
thread: pool-1-thread-2 execute task: 2
thread: pool-1-thread-4 execute task: 14
thread: pool-1-thread-3 execute task: 13
size of queue: 6
thread: pool-1-thread-1 execute task: 3
thread: pool-1-thread-2 execute task: 4
thread: pool-1-thread-3 execute task: 6
thread: pool-1-thread-4 execute task: 5
size of queue: 2
thread: pool-1-thread-1 execute task: 7
thread: pool-1-thread-2 execute task: 8
thread: pool-1-thread-3 execute task: 9
thread: pool-1-thread-4 execute task: 10
size of queue: 0
thread: pool-1-thread-1 execute task: 11
thread: pool-1-thread-2 execute task: 12

结合上面的运行日志,来看看线程池执行的过程,
->日志前两行:线程池有两个核心线程,去执行两个任务,工作队列空闲
->日志3~12行:线程池核心线程已满,再来任务放入工作队列中
->日志13~14行:此时线程池核心线程已满,工作队列已满(放了10个任务),再来两个任务创建两个线程。(此时线程池有四个线程)
->接下来任务1 2 13 14被线程1 2 3 4执行完成
->线程池从工作队列拿出任务3 4 5 6 再去让线程1 2 3 4执行 工作队列还剩下6个任务
->线程池从工作队列拿出任务7 8 9 10 再去让线程1 2 3 4执行 工作队列还剩下2个任务
->线程池从工作队列拿出任务11 12 再去让线程1 2 执行 工作队列还剩下0个任务
->所有任务执行完成,线程池关闭

二 饱和策略

这里注意:我刚刚好提交了14个任务,如果再来一个任务,线程池已经饱和了,就会使用饱和策略来处理提交的任务,饱和策略这里我用了AbortPolicy,线程池会直接抛出异常如下

Exception in thread "main" java.util.concurrent.RejectedExecutionException: Task java.util.concurrent.FutureTask@ca494b rejected from java.util.concurrent.ThreadPoolExecutor@1a4f24f[Running, pool size = 4, active threads = 4, queued tasks = 10, completed tasks = 0]

几种饱和策略:

  1. AbortPolicy:直接抛出异常
  2. CallerRunsPolicy:只用调用者所在线程来运行任务
  3. DiscardOldestPolicy:丢弃队列里最近的一个任务,并执行当前任务
  4. DiscardPolicy:不处理,不丢弃

读者可以每一种都去写个Demo试试看,具体使用哪种饱和策略,要结合具体的生产需求。后面我们讲线程池的合理使用会讲到。

你可能感兴趣的:(Java并发)