Executor并发框架——Executors工厂类
开发中主要使用Executors提供的工厂方法创建线程池,返回的线程池都实现了ExecutorService接口。Executors还包括ExecutorService、ScheduledExecutorService、Callable 类的工厂和实用方法。下面介绍使用最多的四种创建线程池方法
Executors.newCachedThreadPool()
Executors.newFixedThreadPool(int corePoolSize)
Executors.newScheduledThreadPool(int corePoolSize)
Executors.newSingleThreadExecutor()
1.newCachedThreadPool
创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。cache池线程数支持0-Integer.MAX_VALUE(显然完全没考虑主机的资源承受能力)
@Test
public void testCachedThreadPool() throws InterruptedException {
//线程计数器,每执行完成一条线程,调用countDown()使计数器减1,主线程调用方法await()使其等待,当计数器为0时才被执行
CountDownLatch latch = new CountDownLatch(10);
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
Thread.sleep(1000);
cachedThreadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
// 执行完毕,计数器减1
latch.countDown();
}
});
}
// 主线程等待
latch.await();
}
线程名都一样说明线程被回收
2.newFixedThreadPool
创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
定长线程池的大小最好根据系统资源进行设置。如核心数Runtime.getRuntime().availableProcessors()
@Test
public void testFixedThreadPool() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(10);
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(5);
for (int i = 0; i < 10; i++) {
Thread.sleep(1000);
fixedThreadPool.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
latch.countDown();
}
});
}
latch.await();
}
测试发现线程数固定,超出的线程会在队列中等待。
3.newScheduledThreadPool
创建一个定长线程池,支持定时及周期性任务执行。
@Test
public void testScheduledThreadPool() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(1);
//返回ScheduledThreadPoolExecutor对象,实现了ScheduledExecutorService
ScheduledThreadPoolExecutor scheduledExecutorService = (ScheduledThreadPoolExecutor) Executors.newScheduledThreadPool(10);
//3秒后执行定时任务
scheduledExecutorService.schedule(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
latch.countDown();
}
},3000, TimeUnit.MILLISECONDS);
latch.await();
}
4.newSingleThreadExecutor
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
@Test
public void testSingleThreadExecutor() throws InterruptedException {
CountDownLatch latch = new CountDownLatch(10);
ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
for (int i = 0; i <10 ; i++) {
singleThreadExecutor.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName());
latch.countDown();
}
});
}
latch.await();
}
测试发现线程名都一样,说明为单一线程
最近阿里的Java开发规范建议:
线程池不允许使用Executors去创建,而是通过ThreadPoolExecutor的方式,这样的处理方式让写的同学更加明确线程池的运行规则,规避资源耗尽的风险。Executors各个方法的弊端:
1)newFixedThreadPool和newSingleThreadExecutor:
主要问题是堆积的请求处理队列可能会耗费非常大的内存,甚至OOM。
2)newCachedThreadPool和newScheduledThreadPool:
主要问题是线程数最大数是Integer.MAX_VALUE,可能会创建数量非常多的线程,甚至OOM。
想要熟悉自定义创建ThreadPoolExecutor,可以参考(有例子):
http://blog.csdn.net/qq_23146763/article/details/79181871