zoukankan      html  css  js  c++  java
  • java中常见的四种线程池

    前言:

    我们之前使用线程的时候都是使用new Thread来进行线程的创建,但是这样会有一些问题。如:

    a. 每次new Thread新建对象性能差。
    b. 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致死机或oom。
    c. 缺乏更多功能,如定时执行、定期执行、线程中断。
    相比new Thread,Java提供的四种线程池的好处在于:
    a. 重用存在的线程,减少对象创建、消亡的开销,性能佳。
    b. 可有效控制最大并发线程数,提高系统资源的使用率,同时避免过多资源竞争,避免堵塞。
    c. 提供定时执行、定期执行、单线程、并发数控制等功能。

    而我们今天来学习和掌握另外一个新的技能,特别像一个线程池的一个接口类ExecutorService,下面我们来了解下java中Executors的线程池

    Java通过Executors提供四种线程池,分别为:

      newCachedThreadPool:创建一个可缓存的线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。

      newFixedThreadPool:创建一个定长的线程池,可控制线程的最大并发数,超出的线程在队列中等待。

      看看Executors工厂内部是如何实现的

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

      

      可以看到返回的是一个ThreadPoolExecutor对象,核心线程数和是最大线程数都是传入的参数,存活时间是0,时间单位是毫秒,阻塞队列是无界队列LinkedBlockingQueue。

      由于队列采用的是无界队列LinkedBlockingQueue,最大线程数maximumPoolSize和keepAliveTime都是无效参数,拒绝策略也将无效,为什么?

      这里又延伸出一个问题,无界队列说明任务没有上限,如果执行的任务比较耗时,那么新的任务会一直存放在线程池中,线程池的任务会越来越多

      示例代码:

        

    public class Main {
    
        public static void main(String[] args){
            ExecutorService pool = Executors.newFixedThreadPool(4);
    
            for (int i = 0; i < 8; i++) {
                int finalI = i + 1;
                pool.submit(() -> {
                    try {
                        System.out.println("任务"+ finalI +":开始等待2秒,时间:"+LocalTime.now()+",当前线程名:"+Thread.currentThread().getName());
                        Thread.sleep(2000);
                        System.out.println("任务"+ finalI +":结束等待2秒,时间:"+LocalTime.now()+",当前线程名:"+Thread.currentThread().getName());
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                });
    
            }
            pool.shutdown();
        }
    }

      newCachedThreadPool方法也是返回ThreadPoolExecutor对象,核心线程是0,最大线程数是Integer的最MAX_VALUE,存活时间是60,时间单位是秒,SynchronousQueue队列。

      从传入的参数可以得知,在newCachedThreadPool方法中的空闲线程存活时间时60秒,一旦超过60秒线程就会被终止。这边还隐含了一个问题,如果执行的线程较慢,而提交任务的速度快于线程执行的速度,那么就会不断的创建新的线程,从而导致cpu和内存的增长。

      代码和newFixedThreadPool一样循环添加新的线程任务,我的电脑运行就会出现如下错误

      newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。

      

    看看Executors工厂内部是如何实现的

    public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
        return new ScheduledThreadPoolExecutor(corePoolSize);
    }
    

    这里返回的是ScheduledThreadPoolExecutor对象,我们继续深入进去看看

    public ScheduledThreadPoolExecutor(int corePoolSize) {
        super(corePoolSize, Integer.MAX_VALUE, 0, NANOSECONDS,
              new DelayedWorkQueue());
    }
    

    这里调用的是父类的构造函数,ScheduledThreadPoolExecutor的父类是ThreadPoolExecutor,所以返回的也是ThreadPoolExecutor对象。核心线程数是传入的参数corePoolSize,线程最大值是Integer的MAX_VALUE,存活时间时0,时间单位是纳秒,队列是DelayedWorkQueue。

    public class ScheduledThreadPoolExecutor
            extends ThreadPoolExecutor
            implements ScheduledExecutorService {}
    

    下面是ScheduledExecutorService的一些方法

    public interface ScheduledExecutorService extends ExecutorService {
    	//delay延迟时间,unit延迟单位,只执行1次,在经过delay延迟时间之后开始执行
        public ScheduledFuture<?> schedule(Runnable command,long delay, TimeUnit unit);
        public <V> ScheduledFuture<V> schedule(Callable<V> callable,long delay, TimeUnit unit);
    	//首次执行时间时然后在initialDelay之后,然后在initialDelay+period 后执行,接着在 initialDelay + 2 * period 后执行,依此类推
        public ScheduledFuture<?> scheduleAtFixedRate(Runnable command,long initialDelay,
                                                      long period,
                                                      TimeUnit unit);
    	//首次执行时间时然后在initialDelay之后,然后延迟delay时间执行
        public ScheduledFuture<?> scheduleWithFixedDelay(Runnable command,
                                                         long initialDelay,
                                                         long delay,
                                                         TimeUnit unit);
    }

      newSingleThreadExecutor :创建一个单线程化的线程池,它只会有唯一的工作线程来执行任务,保证所有任务按照指定顺序执行。

    参考链接:https://www.cnblogs.com/fixzd/p/9125737.html

  • 相关阅读:
    git分支合并
    php错误处理
    php面试全套
    php面试的那些“黑话”
    快速在命令窗口打开当前路径
    @Autowired注解的使用方法
    jsp页面获取表单的值
    jsp打印九九乘法表
    Google hack
    java中的集合collection
  • 原文地址:https://www.cnblogs.com/nyhhd/p/13434255.html
Copyright © 2011-2022 走看看