java并发之Executors类
newFixedThreadPool
一种线程数量固定的线程池,当线程处于空闲状态时,他们并不会被回收,除非线程池被关闭。当所有的线程都处于活动状态时,新的任务都会处于等待状态,直到有线程空闲出来。
/** * 描述:newFixedThreadPool */ public class FixedThreadPoolTest { public static void main(String[] args) { ExecutorService executorService = Executors.newFixedThreadPool(4); for (int i = 0; i < 1000; i++) { executorService.execute(new Task()); } } } class Task implements Runnable { @Override public void run() { try { Thread.sleep(500); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()); } }
corePoolSize和maxPoolSize是相等的,固定线程数,线程队列无上限
public static ExecutorService newFixedThreadPool(int nThreads) { return new ThreadPoolExecutor(nThreads, nThreads, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>()); }
newSingleThreadExecutor
创建单个线程。它适用于需要保证顺序地执行各个任务;并且在任意时间点,不会有多个线程是活动的应用场景。
public class SingleThreadExecutor { public static void main(String[] args) { ExecutorService executorService = Executors.newSingleThreadExecutor(); for (int i = 0; i < 1000; i++) { executorService.execute(new Task()); } } }
corePoolSize和maxPoolSize是1,单线程,线程队列无上限
public static ExecutorService newSingleThreadExecutor() { return new FinalizableDelegatedExecutorService (new ThreadPoolExecutor(1, 1, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<Runnable>())); }
newCachedThreadPool
创建一个根据需要创建新线程的线程池,但在可用时将重新使用以前构造的线程, 如果没有可用的线程,将创建一个新的线程并将其添加到该池中。 未使用六十秒的线程将被终止并从缓存中删除。
public class CachedThreadPool { public static void main(String[] args) { ExecutorService executorService = Executors.newCachedThreadPool(); for (int i = 0; i < 1000; i++) { executorService.execute(new Task()); } } }
corePoolSize为0表示无核心线程,都可回收,maxPoolSize为无上限,队列为不存储线程
public static ExecutorService newCachedThreadPool() { return new ThreadPoolExecutor(0, Integer.MAX_VALUE, 60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>()); }
newScheduledThreadPool
创建一个线程池,可以调度命令在给定的延迟之后运行,或定期执行, 支持执行定时性或周期性任务。
public class ScheduledThreadPoolTest { public static void main(String[] args) { ScheduledExecutorService threadPool = Executors.newScheduledThreadPool(10); // threadPool.schedule(new Task(), 5, TimeUnit.SECONDS); threadPool.scheduleAtFixedRate(new Task(), 1, 3, TimeUnit.SECONDS); } }
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) { return new ScheduledThreadPoolExecutor(corePoolSize); }
newWorkStealingPool
创建一个维护足够的线程以支持给定的并行级别的线程池,并且可以使用多个队列来减少争用。 ( jdk1.8版本新增的方法 )
- 会创建子任务,并且放入自己的队列当中(子任务最好不加锁,会影响其它线程执行子任务)
- 空闲的线程会帮助其它线程处理子任务(窃取)
4种线程池的构造参数
Parameter |
FixedThreadPool |
CachedThreadPool |
ScheduledThreadPool |
SingleThreaded |
corePoolSize |
constructor-arg |
0 |
constructor-arg |
1 |
maxPoolSize |
same as corePoolSize |
Integer.MAX_VALUE |
Integer.MAX_VALUE |
1 |
keepAliveTime |
0 seconds |
60 seconds |
0 seconds |
0 seconds |
阻塞队列分析
- FixedThreadPool和SingleThreaded的Queue参数类型为什么是LinkedBlockingQueue(无界队列)?
FixedThreadPool和SingleThreaded这两种线程池的corePoolSize和maxPoolSize是相等的,线程的数量是固定的,当大量并发任务时,只能放入队列当中等待处理,所以队列的容量 设为无限,选择LinkedBlockingQueue类型
- CachedThreadPool的Queue类型为什么是是SynchronousQueue(直接交接)?
SynchronousQueue表示不存放线程,因为corePoolSize为0,maxPoolSize为Integer.MAX_VALUE,当大量并发时,每个任务都创建一个线程来处理,所以不需要队列存放线程。并当 线程空闲60秒就会被回收。
总结
Executors类中的创建线程池的方法都是设计好的,有一些局限性。实际根据不同的业务场景,自己设置线程池参数,如内存大小,线程名等等。