三.多线程JUC篇-3.16 Executors

2.useCachedThreadPool

创建一个可按需自动扩容的线程池,但是会优先重用线程池中空闲可用的线程。这个类型的线程池将会大大提升执行许多短暂的异步任务的程序。

public static ExecutorService newCachedThreadPool(ThreadFactory threadFactory) {
        return new ThreadPoolExecutor(0, 2147483647, 60L, TimeUnit.SECONDS,
         new SynchronousQueue(), threadFactory);
    }

将corePoolSize设置为0,maximumPoolSize设置为Integer.MAX_VALUE,使用了SynchronousQueue,也就是说来了任务就创建线程运行,当线程空闲超过60s就销毁线程。

  • 常驻线程数为0
  • Integer.MAX_VALUE非常大,可以认为是可以无限创建线程的,在资源有限的情况下容易引起OOM异常
  • 线程空闲1分钟后,会自动回收
  • SynchronousQueue是一个内部只能包含一个元素的队列。插入元素到队列的线程被阻塞,直到另一个线程从队列中获取了队列中存储的元素。同样,如果线程尝试获取元素并且当前不存在任何元素,则该线程将被阻塞,直到线程将元素插入队列。将这个类称为队列有点夸大其词。这更像是一个点。
  • 当线程池中所有线程终止了,且(线程空闲60秒后)被回收了,useCachedThreadPool会自动终止

2.1 使用场景

  • 大量、短暂的任务
  • 一些面向连接的daemon型SERVER中用得不多
  • 任务很长、任务又多,很容易造成OOM

2.2 注意

虽然newCachedThreadPool中写着“会优先重用线程池中空闲的线程”,但是Thread的start()方法中又注明了多次启动一个线程是非法的。特别是当线程已经结束执行后,不能再重新启动。

//在线程的操作中,如果 T 是一个 Thread 的实现类 
T t = new T(); 
t.start(); 
t.start(); 
那么会抛出  java.lang.IllegalThreadStateException 异常。

但是这样写就可以

T t = new T(); 
ExecutorService newCachedThreadPool = Executors.newCachedThreadPool(); 
newCachedThreadPool.submit(t); 
newCachedThreadPool.submit(t); 

查阅源码可以发现,newCachedThreadPool方法中使用的ThreadExecutorPool类的构造函数如下:

public ThreadPoolExecutor(int corePoolSize,
                              int maximumPoolSize,
                              long keepAliveTime,
                              TimeUnit unit,
                              BlockingQueue<Runnable> workQueue) {
        this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
             Executors.defaultThreadFactory(), defaultHandler);
    }

//线程池有一个 defaultThreadFactory , 实际也是每次 new 出来一个新的线程. 
ThreadFactory tf = Executors.defaultThreadFactory(); 
for (int i = 0; i < 10; i++) { 
    Thread tft = tf.newThread(t); 
    tft.start(); 

3.newFixedThreadPool

定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。每次线程池中最多只有nThreads个线程

public static ExecutorService newFixedThreadPool(int nThreads) {
    return new ThreadPoolExecutor(nThreads, nThreads,
                                  0L, TimeUnit.MILLISECONDS,
                                  new LinkedBlockingQueue<Runnable>());
}
  • LinkedBlockingQueue大小Integer.MAX_VALUE
  • 当线程池中所有线程终止了,不会像useCachedThreadPool会自动销毁
  • 可以理解为一批批nThreads数量的任务执行

4.newSingleThreadExecutor

单线程线程池,用唯一的线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。

public static ExecutorService newSingleThreadExecutor() {
    return new FinalizableDelegatedExecutorService
        (new ThreadPoolExecutor(1, 1,
                                0L, TimeUnit.MILLISECONDS,
                                new LinkedBlockingQueue<Runnable>()));
}
  • 现在返回的不是ThreadPoolExecutor,而是ExecutorService, 是为了仅仅返回ExecutorService的方法, 而将一些ThreadPoolExecutor特有的方法(如getActiveCount())不暴露出来
  • 与Thread的区别,Thread执行完后会结束 ,而SingleThread不会;SingleThread有一个等待队列

5.newWorkStealingPool

在Java 8中,引入了一种新型的线程池,作为newWorkStealingPool()来补充现有的线程池。WorkStealingPool线程池,来维持相应的并行级别,它会通过工作窃取的方式,使得多核的 CPU 不会闲置,总会有活着的线程让 CPU 去运行。

顾名思义,它基于工作窃取算法,其中任务可以生成其他较小的任务,这些任务将添加到并行处理线程的队列中。如果一个线程完成了工作并且无事可做,则可以从另一线程的队列中“窃取”工作。
  
newWorkStealingPool适合使用在很耗时的操作,但是newWorkStealingPool不是ThreadPoolExecutor的扩展,它是新的线程池类ForkJoinPool的扩展,但是都是在统一的一个Executors类中实现,由于能够合理的使用CPU进行对任务操作(并行操作),所以适合使用在很耗时的任务中
在这里插入图片描述

   public static ExecutorService newWorkStealingPool() {
        return new ForkJoinPool(Runtime.getRuntime().availableProcessors(), ForkJoinPool.defaultForkJoinWorkerThreadFactory, (UncaughtExceptionHandler)null, true);
    }
  • 实现的是ForkJoinPool,而不是ThreadPoolExecutor
  • 一次执行多少个线程,与CPU核数相关
  • WorkStealingPool是守护线程,使用ForkJoinPool实现的WorkStealingPool根据当前操作系统的CPU有几个核就会创建几个线程
  • WorkStealingPool能够合理的使用CPU进行对任务操作(并行操作)适合使用在很耗时的操作
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值