使用线程池的好处:1、线程可以复用,减少创建、销毁线程的资源开销;2、避免创建线程,提高效率;3、便于对线程统一管理、监控等。大神Doug Lea为我们提供了多种构建线程池的方法:
1、直接构造ThreadPoolExecutor对象
源码分析:
//构造方法1:使用默认的线程工厂,默认的拒绝策略(中止策略,直接抛RejectedExecutionException)
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), defaultHandler);
}
//构造方法2:可以自定义线程工厂
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);
}
//构造方法3:可以自定义拒绝策略
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
RejectedExecutionHandler handler) {
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
Executors.defaultThreadFactory(), handler);
}
//构造方法4:可以自定义线程工厂和拒绝策略
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
使用示例:
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 直接构造线程池,new ThreadPoolExecutor
* 使用灵活,方便扩展
*/
public class ThreadPoolExecutorTest {
private static final int CORE_POOL_SIZE=10;
private static final int MAXIMUM_POOL_SIZE=15;
private static final int KEEP_ALIVE_TIME=0;
//使用有界队列(Integer.MAX_VALUE)和Executors.newFixedThreadPool类似
private ExecutorService threadPoolExecutor=new ThreadPoolExecutor(
CORE_POOL_SIZE, //核心工作线程数
MAXIMUM_POOL_SIZE, //线程池最大线程数
KEEP_ALIVE_TIME, //空闲线程等待任务的时间
TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()//有界队列(Integer.MAX_VALUE),可以改为必须指定长度的有界队列ArrayBlockingQueue
//ThreadFactory 可以指定线程构造工厂
//RejectedExecutionHandler 可以指定队列满后的拒绝策略,理论来说如果队列太长,则此策略不易被触发
);
//指定队列长度,要注意拒绝策略
private ExecutorService threadPoolExecutor2=new ThreadPoolExecutor(
CORE_POOL_SIZE, //核心工作线程数
MAXIMUM_POOL_SIZE, //线程池最大线程数
KEEP_ALIVE_TIME, //空闲线程等待任务的时间
TimeUnit.MILLISECONDS,
new ArrayBlockingQueue<Runnable>(5),//10个工作,5个扩展,5个排队,理论上最多并发15个,排队5个,超过数量会触发拒绝策略
//ThreadFactory 可以指定线程构造工厂
new ThreadPoolExecutor.AbortPolicy() //中止执行策略,抛异常
//其他几种拒绝策略是:
//ThreadPoolExecutor.CallerRunsPolicy//立即执行
//ThreadPoolExecutor.DiscardPolicy//丢弃当前,不做处理
//ThreadPoolExecutor.DiscardOldestPolicy//丢弃最早的,立即执行当前线程
//可见几种策略都不太好用
);
public ThreadPoolExecutorTest() {
}
private void test() {
for(int i=0;i<100;i++) {
final int num=i;
threadPoolExecutor.submit(new Runnable() {
public void run() {
System.out.println("num:"+num);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
threadPoolExecutor.shutdown();
}
private void test2() {
for(int i=0;i<100;i++) {
final int num=i;
threadPoolExecutor2.submit(new Runnable() {
public void run() {
System.out.println("num:"+num);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
threadPoolExecutor2.shutdown();
}
public static void main(String[] args) {
ThreadPoolExecutorTest threadPoolExecutorTest=new ThreadPoolExecutorTest();
//threadPoolExecutorTest.test();
threadPoolExecutorTest.test2();
}
}
2、通过Executors工具类创建
2.1、Executors.newFixedThreadPool构造一个固定工作线程数量,有个有界队列(Integer.MAX_VALUE)可以支持排队的线程池
源码分析:
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>());
}
可见,最终构造的还是ThreadPoolExecutor对象,其中corePoolSize=maximumPoolSize,空闲线程不会等待,有个有界队列(Integer.MAX_VALUE)负责缓存排队(注意没有指定长度)
使用示例:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
/**
* 固定数量的工作线程,有有界队列(Integer.MAX_VALUE)支持排队进入
*/
public class FixedThreadPoolTest {
private ExecutorService fixedThreadPool = Executors.newFixedThreadPool(10);//固定线程池数量
/**
*
*/
public FixedThreadPoolTest() {
}
private void test() {
for (int i = 0; i < 100; i++) {
final int num = i;
fixedThreadPool.submit(new Runnable() {
public void run() {
System.out.println("NO:" + num + ",Name:" + Thread.currentThread().getName());
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
fixedThreadPool.shutdown();
}
public static void main(String[] args) {
FixedThreadPoolTest fixedThreadPoolTest = new FixedThreadPoolTest();
fixedThreadPoolTest.test();
}
}
2.2、Executors.newSingleThreadExecutor构造一个只有一个工作线程的线程池,其和newFixedThreadPool一样,也有个有界队列(Integer.MAX_VALUE)支持任务排队
源码分析:
//corePoolSize=maximumPoolSize=1,外加一个有界队列(Integer.MAX_VALUE)支持排队
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue<Runnable>()));
}
使用示例:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
* 固定线程大小为1,有个有界队列(Integer.MAX_VALUE)可以方便排队
*/
public class SingleThreadExecutorTest {
private ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
public SingleThreadExecutorTest() {
}
private void test() {
for (int i = 0; i < 100; i++) {
final int num = i;
singleThreadExecutor.submit(new Runnable() {
public void run() {
System.out.println("num:" + num);
}
});
}
singleThreadExecutor.shutdown();
}
public static void main(String[] args) {
SingleThreadExecutorTest singleThreadExecutorTest = new SingleThreadExecutorTest();
singleThreadExecutorTest.test();
}
}
2.3、Executors.newCachedThreadPool创建一个根据需要创建新线程的线程池,但在可用时将重新使用以前构造的线程。 这些池通常会提高执行许多短暂异步任务的程序的性能。 调用execute将重用以前构造的线程(如果可用)。 如果没有可用的线程,将创建一个新的线程并将其添加到该池中。 未使用六十秒的线程将被终止并从缓存中删除。 因此,长时间保持闲置的池将不会消耗任何资源。
源码分析:
//注意:其和newFixedThreadPool/newSingleThreadExecutor是不一样的,
//其空闲线程的超时时间是60秒,且使用了SynchronousQueue一个不存储元素的阻塞队列,
//每一个put操作必须等待一个take操作,否则不能继续添加元素
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
使用示例:
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
/**
* 创建一个根据需要创建新线程的线程池,但在可用时将重新使用以前构造的线程。 这些池通常会提高执行许多短暂异步任务的程序的性能。
* 调用execute将重用以前构造的线程(如果可用)。 如果没有可用的线程,将创建一个新的线程并将其添加到该池中。
* 未使用六十秒的线程将被终止并从缓存中删除。 因此,长时间保持闲置的池将不会消耗任何资源。
*/
public class CachedThreadPoolTest {
private ExecutorService cachedThreadPool = Executors.newCachedThreadPool();//可以看做是没有排队队列,有线程就执行了
//自定义,看是否会阻塞
private ExecutorService cachedThreadPool2= new ThreadPoolExecutor(
5,
10,
60L,
TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());//本构造限定了大小,而这里又类似没有队列,会导致线程池满后抛异常
public CachedThreadPoolTest() {
}
private void test() {
for (int i = 0; i < 100; i++) {
final int num = i;
cachedThreadPool.submit(new Runnable() {
public void run() {
System.out.println("num:" + num);
}
});
}
cachedThreadPool.shutdown();
}
private void test2() {
for (int i = 0; i < 100; i++) {
final int num = i;
cachedThreadPool2.submit(new Runnable() {
public void run() {
System.out.println("num:" + num);
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
});
}
System.out.println("循环完了");
cachedThreadPool2.shutdown();
}
public static void main(String[] args) {
CachedThreadPoolTest cachedThreadPoolTest=new CachedThreadPoolTest();
//cachedThreadPoolTest.test();
cachedThreadPoolTest.test2();
}
}
2.4、Executors.newScheduledThreadPool创建一个线程池,可以调度命令在给定的延迟之后运行,或定期执行。
源码分析:
//注意这里构造的是:ScheduledThreadPoolExecutor
public static ScheduledExecutorService newScheduledThreadPool(int corePoolSize) {
return new ScheduledThreadPoolExecutor(corePoolSize);
}
使用示例:
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
/**
* 可以延时执行,或定时执行,用到了:DelayedWorkQueue
*/
public class ScheduledThreadPoolTest {
private ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(10);
private SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
public ScheduledThreadPoolTest() {
}
private String getCurrentTime() {
return simpleDateFormat.format(Calendar.getInstance().getTime());
}
private void test() {
// 就像其他线程池一样直接执行任务
/*
scheduledThreadPool.submit(new Runnable() {
public void run() {
System.out.println("直接执行");
}
});
*/
// 延时执行后,再按固定间隔执行
/*
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
public void run() {
System.out.println(getCurrentTime()+" scheduleWithFixedDelay");
}
}, 1, 2, TimeUnit.SECONDS);
*/
// 延时执行后,再定时执行
scheduledThreadPool.scheduleWithFixedDelay(new Runnable() {
public void run() {
System.out.println(getCurrentTime()+" scheduleWithFixedDelay");
}
}, 1, 2, TimeUnit.SECONDS);
}
public static void main(String[] args) {
ScheduledThreadPoolTest scheduledThreadPoolTest=new ScheduledThreadPoolTest();
scheduledThreadPoolTest.test();
}
}