美文网首页
JAVA多线程-线程池使用详解

JAVA多线程-线程池使用详解

作者: Lugton | 来源:发表于2020-03-23 15:15 被阅读0次

    为什么要用线程池:
    1.减少了创建和销毁线程的次数,每个工作线程都可以被重复利用,可执行多个任务。
    2.可以根据系统的承受能力,调整线程池中工作线线程的数目,防止因为消耗过多的内存,而把服务器累趴下(每个线程需要大约1MB内存,线程开的越多,消耗的内存也就越大,最后死机)。

    一、常用的线程池

    FixedThreadPool:返回一个固定数量的线程池。该线程池中的线程数量始终不变。当有一个新的任务提交时,线程池中若有空闲线程,则立即执行。若没有,则会暂存在任务队列中,等到有空闲线程时执行。

    Executors.newFixedThreadPool(int):执行长期任务性能好

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

    SingleThreadExecutor:只有一个线程的线程池,按顺序执行

    Executors.newSingleThreadExecutor():一个一个任务执行

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

    CachedThreadPool:线程数量不确定,若有空闲线程,则优先选择,若无空闲线程,则会创建新的线程。线程执行完毕后会返回线程池复用。

    Executors.newCachedThreadPool():短期异步小程序或负载较轻的服务器

    public static ExecutorService newCachedThreadPool() {
            return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
                                          60L, TimeUnit.SECONDS,
                                          new SynchronousQueue<Runnable>());
        }
    

    二、线程池的七大参数
    使用ThreadPoolExecutor创建线程池更值得推荐
    以下是其源码的构造方法,其中包含七个参数:

    public ThreadPoolExecutor(int corePoolSize,
                                  int maximumPoolSize,
                                  long keepAliveTime,
                                  TimeUnit unit,
                                  BlockingQueue<Runnable> workQueue,
                                  ThreadFactory threadFactory,
                                  RejectedExecutionHandler handler) {
            if (corePoolSize < 0 ||
                maximumPoolSize <= 0 ||
                maximumPoolSize < corePoolSize ||
                keepAliveTime < 0)
                throw new IllegalArgumentException();
            if (workQueue == null || threadFactory == null || handler == null)
                throw new NullPointerException();
            this.acc = System.getSecurityManager() == null ?
                    null :
                    AccessController.getContext();
            this.corePoolSize = corePoolSize;
            this.maximumPoolSize = maximumPoolSize;
            this.workQueue = workQueue;
            this.keepAliveTime = unit.toNanos(keepAliveTime);
            this.threadFactory = threadFactory;
            this.handler = handler;
        }
    
    1. corePoolSize:线程池中常驻核心线程数,即最小可以同时运行的线程数量。
    2. maximumPoolSize:线程池能够容纳同时执行的最大线程数
    3. keepAliveTime:多余线程的存活时间,当前线程池数量超过corePoolSize且空闲时间达到keepAliveTime时,多余的空间线程被销毁到剩下corePoolSize。
    4. unit:keepAliveTime的单位
    5. workQueue:任务队列的类型
    6. threadFactory:表示生成线程池中工作线程的线程工厂,用于创建线程一般用默认的即可
    7. handler:拒绝策略。

    三、拒绝策略

    1. 调用者执行(CallerRunsPolicy):任务被线程池拒绝后,任务会被退回到调用者
    2. 终止执行(AbortPolicy):任务被拒绝时,抛出RejectedExecutionException异常报错
    3. 丢弃任务(DiscardPolicy):任务被直接丢弃,不会抛异常报错;
    4. 丢失老任务(DiscardOldestPolicy):把等待队列中最老的任务删除,删除后重新提交当前任务。

    四、案例

    阿里巴巴开发手册中明确表示:


    image.png

    所以我们需要通过ThreadPoolExecutor的方式创建线程:

     ExecutorService executorService=new ThreadPoolExecutor(10,10,60,TimeUnit.MILLISECONDS,new LinkedBlockingDeque<>(1024),new ThreadPoolExecutor.CallerRunsPolicy());
    
            CountDownLatch countDownLatch=new CountDownLatch(10);
    
            for (int i=0;i<10;i++){
                int finalI = i;
                executorService.execute(() -> {
                    System.out.println(finalI);
                    countDownLatch.countDown();
                });
            }
    
    
            try {
                countDownLatch.await();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
    
            executorService.shutdown();
    
            System.out.println("Thread shut down");
    

    相关文章

      网友评论

          本文标题:JAVA多线程-线程池使用详解

          本文链接:https://www.haomeiwen.com/subject/gpviyhtx.html