面试必问系列 创建线程池有哪几种方式?

创建线程池有哪几种方式?

    Executors.newFixedThreadPool(4); 实际实现 new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()) 固定线程数为4 同时超出线程数将放在 LinkedBlockingQueue 中 默认是Integer.MAX_VALUE 可能阻塞过多可能出现 oom Executors.newSingleThreadExecutor(); 实际实现 new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())) 固定线程数为1 和newFixedThreadPool 区别包裹了 FinalizableDelegatedExecutorService 这样就无法转成ThreadPoolExecutor 也就不能修改线程数了 Executors.newScheduledThreadPool(4); 实际实现 new ScheduledThreadPoolExecutor(corePoolSize); 固定线程 返回可定时 可延时 处理的 ScheduledThreadPoolExecutor ScheduledThreadPoolExecutor extends ThreadPoolExecutor implements ScheduledExecutorService Executors.newCachedThreadPool(); 实际实现 new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); 固定线程数为0 可以无限增长Integer.MAX_VALUE 会有oom Executors.newWorkStealingPool(); 实际实现 new ForkJoinPool (Runtime.getRuntime().availableProcessors(), ForkJoinPool.defaultForkJoinWorkerThreadFactory, null, true) java.util.concurrent.ForkJoinPool 适用于耗时长的线程任务 推荐使用 public ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue, ThreadFactory threadFactory, RejectedExecutionHandler handler) 几个参数 核心线程池数 如果运行的线程少于 corePoolSize,则创建新线程来处理任务,即使线程池中的其他线程是空闲的; 如果线程池中的线程数量大于等于 corePoolSize 且小于 maximumPoolSize,则只有当workQueue满时才创建新的线程去处理任务; 如果设置的corePoolSize 和 maximumPoolSize相同,则创建的线程池的大小是固定的,这时如果有新任务提交,若workQueue未满,则将请求放入workQueue中,等待有空闲的线程去从workQueue中取任务并处理; 如果运行的线程数量大于等于maximumPoolSize,这时如果workQueue已经满了,则通过handler所指定的策略来处理任务; 所以,任务提交时,判断的顺序为 corePoolSize –> workQueue –> maximumPoolSize。 最大线程数 空任务回收时长 空任务回收时长单位 超出线程池的任务阻塞队列 直接切换:这种方式常用的队列是SynchronousQueue 使用无界队列:一般使用基于链表的阻塞队列LinkedBlockingQueue。如果使用这种方式,那么线程池中能够创建的最大线程数就是corePoolSize,而maximumPoolSize就不会起作用了(后面也会说到)。当线程池中所有的核心线程都是RUNNING状态时,这时一个新的任务提交就会放入等待队列中 使用有界队列:一般使用ArrayBlockingQueue。使用该方式可以将线程池的最大线程数量限制为maximumPoolSize,这样能够降低资源的消耗,但同时这种方式也使得线程池对线程的调度变得更困难,因为线程池和队列的容量都是有限的值,所以要想使线程池处理任务的吞吐率达到一个相对合理的范围,又想使线程调度相对简单,并且还要尽可能的降低线程池对资源的消耗,就需要合理的设置这两个数量 线程工厂 常用 默认Executors.defaultThreadFactory() 这种会设定默认线程名 和 普通优先级 和 非守护线程 推荐 重写成带线程池名工厂 方便定位问题 超出策略 AbortPolicy:直接抛出异常,这是默认策略; CallerRunsPolicy:用调用者所在的线程来执行任务; DiscardOldestPolicy:丢弃阻塞队列中靠最前的任务,并执行当前任务; DiscardPolicy:直接丢弃任务;

线程池都有哪些状态?

源码中状态定义

// runState is stored in the high-order bits
    private static final int RUNNING    = -1 << COUNT_BITS;
    private static final int SHUTDOWN   =  0 << COUNT_BITS;
    private static final int STOP       =  1 << COUNT_BITS;
    private static final int TIDYING    =  2 << COUNT_BITS;
    private static final int TERMINATED =  3 << COUNT_BITS;
经验分享 程序员 微信小程序 职场和发展