创建线程池
- 创建无界线程池
ExecutorService executor = Executors.newCachedThreadPool();
- 创建固定数量的线程池
ExecutorService executorService = Executors.newFixedThreadPool(3);
- 创建单一线程的线程池
ExecutorService executorService = Executors.newSingleThreadExecutor();
- 创建定时或周期任务的线程池
ScheduledThreadPoolExecutor executor = new ScheduledThreadPoolExecutor(3);
使用Executors创建线程池
一般使用Executors的静态方法创建线程池,需要定制化可以使用ThreadPoolExecutor类进行详细参数设定。
public class ExecutorTest {
public static void main(String[] args) throws InterruptedException {
ExecutorService executorService = Executors.newCachedThreadPool();
for(int i=0;i<5;i++){
final int k = i;
executorService.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" user"+(k+1));
}
});
}
Thread.sleep(3000);
for(int i=0;i<5;i++){
final int k = i;
executorService.execute(new Runnable() {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" user"+(k+1));
}
});
}
}
}
可以观察到使用newCachedThreadPool创建的线程池里面的线程得到了复用,因为线程池线程名称唯一(从源码可以看出默认新创建的线程会保持60秒)
使用Executors的静态方法底层是调用了ThreadPoolExecutor类
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue<Runnable>());
}
使用newCachedThreadPool(ThreadFactory) 替换默认线程工厂
public class MyThreadFactory implements ThreadFactory{
@Override
public Thread newThread(Runnable r) {
Random random = new Random();
Thread thread = new Thread(r);
thread.setName("yuchuan-thread-" + random.nextInt(100));
return thread;
}
}
public class ExecutorTest {
public static void main(String[] args) throws InterruptedException {
MyThreadFactory myThreadFactory = new MyThreadFactory();
ExecutorService executorService = Executors.newCachedThreadPool(myThreadFactory);
executorService.execute(new Runnable() {
@Override
public void run() {
System.out.println("running " + Thread.currentThread().getName());
}
});
}
}
ThreadPoolExecutor 使用Executors的静态方法底层都是调用了ThreadPoolExecutor类
ThreadPoolExecutor(int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit unit, BlockingQueue<Runnable> workQueue)
线程池核心数量与任务数关系
如果线程数量 < corePoolSize 则直接执行任务,不放入扩展队列Queue中。
ThreadPoolExecutor executor = new ThreadPoolExecutor(7,8,5,TimeUnit.SECONDS,new LinkedBlockingDeque<Runnable>())
如果corePoolSize < 线程数量 < maximumPoolSize且队列使用LinkedBlockingDeque,则放入队列;如果队列使用SynchronousQueue类,会立即执行,且当时间keepAliveTime超过5秒时,清除空闲线程。
BlockingQueue 常用的实现类LinkedBlockingQueue 和ArrayBlockingQueue。用 LinkedBlockingQueue的好处在于没有大小限制,所以执行execute()不会抛出异常。线程池中运行的线程数也永远不会超过corePoolSize,因为其他多于的线程被放入LinkedBlockingQueue队列,keepAliveTime参数也就没有意义。
如果线程数量 > maximumPoolSize 且队列使用 LinkedBlockingQueue 则会放入队列;若队列使用 SynchronousQueue 则会抛出拒绝异常
shutdown() VS shutdownNow()
方法shutdown()的作用是使当前未执行完的线程继续执行,而不再添加新的任务task,还有shutdown()方法不会阻塞,调用shutdown()方法后,主线程main就马上结束了,而线程池会继续运行直到所有任务执行完才会停止。如果不调用shutdown()方法,那么线程池会一直保持下去,以便随时执行被添加的task任务。
方法shutdownNow()的作用是中断所有的任务task,并且抛出InterruptedException异常,前提是在Runnable中使用if(Thread.currentThread.isInterrupted()==true)语句来判断当前线程的中断状态,而未执行的线程不再执行,也就是从执行队列中清除。如果没有if(Thread.currentThread.isInterrupted()==true)语句及抛出异常的代码,则池中正在运行的线程直到执行完毕,而未执行的线程将不再执行,也从执行队列中清除。
public class MyRunnable1 implements Runnable {
@Override
public void run() {
System.out.println(Thread.currentThread().getName()+" " + System.currentTimeMillis());
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+" end");
}
}
public class ExecutorTest {
public static void main(String[] args) throws InterruptedException {
MyRunnable1 myRunnable1 = new MyRunnable1();
ThreadPoolExecutor pool =