JUC编程(六)-线程池

九.线程池

线程过多会带来调度开销,进而影响缓存局部性和整体性能。而线程池可以事先创建多个线程,等待着CPU分配执行任务,执行完之后返回池中等待下一次任务。这避免了在处理短时间任务时创建与销毁线程的代价。线程池不仅能够保证内核的充分利用,还能防止过分调度,优化资源的使用。

三大方法:

  • ExecutorService service = Executors.newSingleThreadExecutor();                  创建一个使用从*队列运行的单个工作线程的执行程序
  • ExecutorService service = Executors.newFixedThreadPool(int nThreads);     创建一个线程池,该线程池重用固定数量的从共享*队列中运行的线程。
  • ExecutorService service = Executors.newCachedThreadPool();                       创建一个根据需要创建新线程的线程池,但在可用时将重新使用以前构造的线程
  • public class Executor1 {
        public static void main(String[] args) {
            // ExecutorService service = Executors.newSingleThreadExecutor();
            // 创建单个线程
            // ExecutorService service = Executors.newFixedThreadPool(3);
            // 创建固定线程数的线程池
            ExecutorService service = Executors.newCachedThreadPool();
            // 可变数量线程数的线程池
            try {
                for (int i = 1; i <= 15; i++) {
                    service.execute(()->{
                        System.out.println(Thread.currentThread().getName()+" start");
                    });
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                service.shutdown();
            }
        }
    }

七大参数:

  • int corePoolSize                                            核心线程数                                
  • int maximumPoolSize                                  最大线程数                           
  • long keepAliveTime                                      除核心线程以外多余空闲线程的等待时间,超过会被终止                              
  • TimeUnit unit                                                等待时间单位                            
  • BlockingQueue<Runnable> workQueue    阻塞队列(任务等待执行队列)                           
  • ThreadFactory threadFactory                      线程工厂,一般不用改动                            
  • RejectedExecutionHandler handler             拒绝策略,任务队列已满且执行任务的线程数大于最大线程数时启用 

自定义线程池

public class Threadpool {
    public static void main(String[] args) {
        /*  拒绝策略
            AbortPolicy()  被拒绝的任务的处理程序,抛出一个 RejectedExecutionException
            CallerRunsPolicy()  一个被拒绝的任务的处理程序,直接在 execute方法的调用线程中运行被拒绝的任务,除非执行程序已经被关闭,否则这个任务被丢弃
            DiscardOldestPolicy()  被拒绝的任务的处理程序,丢弃最旧的未处理请求,然后重试 execute ,除非执行程序关闭,在这种情况下,任务被丢弃
            DiscardPolicy()  被拒绝的任务的处理程序静默地丢弃被拒绝的任务
         */
        ExecutorService service = new ThreadPoolExecutor(
                2,//核心线程数
                6,//最大线程数
                3,//等待时间
                TimeUnit.SECONDS,//时间单位
                new ArrayBlockingQueue<>(3),//阻塞队列 
                Executors.defaultThreadFactory(),//默认的线程工厂
                new ThreadPoolExecutor.DiscardOldestPolicy()
        );
        try {
            for (int i = 1; i <= 15; i++) {
                service.execute(()->{
                    System.out.println(Thread.currentThread().getName()+" start");
                });
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            service.shutdown();
        }
    }
}

如何确定最大线程数(maximumPoolSize):

获取CPU核数:

Runtime.getRuntime().availableProcessors()
  • CPU密集型:(系统的硬盘、内存性能相对CPU要好很多,即需要大量的运算)  可设置为CPU核数。 参考:cores+1
  • I/O密集型:(系统的CPU性能相对硬盘、内存要好很多,即需要大量的I/O操作)  大于I/O十分耗时的任务数量的2倍。参考:2 * cores
上一篇:Java 异步任务执行服务 基本概念和原理


下一篇:executorService.invokeAll执行一批任务