线程池的三个使用方式

Executor 读音[ɪɡˈzekjətə(r)]-一个贼可特
Thread 读音[θred]-思略的
  1. Executors.newFixedThreadPool(5) 一池固定线程 适合长期任务,性能好,执行无序
  2. Executors.newSingleThreadExecutor() 一池一线程 一个任务一个任务执行,保证顺序性
  3. Executors.newCachedThreadPool() 一池多线程 适合短期异步任务或者负载很轻的服务,类似会扩容
  4. 仅了解-Executors.newScheduledThreadPool() 创建固定大小的线程,可以延迟或定时的执行任务。
  5. 仅了解-java8新出的Executors.newWorkStealingPool(int)

Java中的线程池是通过Executor框架实现的,该框架用到了Executor,Executors[类似于Array与Arrays、Collection与Collections辅助工具类],ExecutorService,ThreadPoolExecutor[线程池底层用这个类]这几个类。

体系结构:

java.util.concurrent.Executor : 负责线程的使用与调度的根接口 
  |--ExecutorService 子接口: 线程池的主要接口 
    |--ThreadPoolExecutor 线程池的实现类 
    |--ScheduledExecutorService 子接口:负责线程的调度 
      |--ScheduledThreadPoolExecutor :继承 ThreadPoolExecutor, 实现 ScheduledExecutorService *

代码演示

/**
 * 线程池三种试用方式
 * @Author小海
 * @Description:
 * @Date: Create in 22:28 2020-02-01
 */
public class ExecutorsDemo {
    public static void main(String[] args) {
        // Executor
        // ThreadPoolExecutor;
        // 一个线程池创建5个固定线程,适合长期任务,性能好
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        // 一个线程池创建1个线程,一个任务一个任务执行,保证顺序性
        executorService = Executors.newSingleThreadExecutor();
        // 一个线程池创建N个线程,适合短期异步任务或者负载很轻的服务
        executorService = Executors.newCachedThreadPool();
        try {
            for (int i = 0; i < 10; i++) {
                // 程序执行结果如下:最多只有5个线程同时执行任务
                // execute只执行
                executorService.execute(()->{
                    System.out.println(Thread.currentThread().getName() + "\t 办理业务");
                });
                // submit带返回值
                executorService.submit(new FutureTask<>(new Callable<Integer>() {
                    @Override
                    public Integer call() throws Exception {
                        return null;
                    }
                }));

                // 模拟长期任务,让线程执行时间变长
                // Thread.sleep(200);
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            // 关闭线程池
            executorService.shutdown();
        }
    }
}


newFixedThreadPool

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}

适用场景:可用于Web服务瞬时削峰,但需注意长时间持续高峰情况造成的队列阻塞。

newSingleThreadExecutor

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}

定眼一看,这里多了一层FinalizableDelegatedExecutorService包装。对比可以看出,FixedThreadPool可以向下转型为ThreadPoolExecutor,并对其线程池进行配置,而SingleThreadExecutor被包装后,无法成功向下转型。因此,SingleThreadExecutor被定以后,无法修改,做到了真正的Single。

newCachedThreadPool

 public static ExecutorService newCachedThreadPool() {
    return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                  60L, TimeUnit.SECONDS,
                                  new SynchronousQueue<Runnable>());
}
  1. corePoolSize = 0,maximumPoolSize = Integer.MAX_VALUE,即线程数量几乎无限制;
  2. workQueue 为 SynchronousQueue 同步队列,这个队列类似于一个接力棒,入队出队必须同时传递,因为CachedThreadPool线程创建无限制,不会有队列等待,所以使用SynchronousQueue;
  3. 适用场景:快速处理大量耗时较短的任务,如Netty的NIO接受请求时,可使用CachedThreadPool。
posted @ 2019-09-17 13:20  要好好吃饭  阅读(479)  评论(0编辑  收藏  举报