线程池的好处
1、线程的创建需要消耗的,用完了马上就扔了比较可惜,所以把它缓存起来,以后还能再用;
2、可以根据实际情况调整线程池的大小,防止线程太多;
3、有些场合可以用线程池来做同步(比如多个线程使用同一文件系统时,可以用SingleThreadExecutor来保持同步);
可缓存(可变大小)的线程池 CachedThreadPool
这是一种很宽松的线程池,当任务来了之后,如果没有可用的线程那么就新建一个,如果有空闲的线程,则直接使用现有的线程。
可以根据实际的处理需求动态变化线程的数量。如果实际处理需求没那么多了,就会把部分线程回收掉。反之,如果实际处理需求又上来了,就会重新创建线程。
比如下面的代码,模拟每隔2秒才有一个新任务,而这个任务每次只需要1秒就能执行完:
public classCachedThreadPool {static Random random = newRandom();static int taskId = 0;static ExecutorService service =Executors.newCachedThreadPool();public static voidmain(String[] args) {while(true) {
service.execute(newMyThread());try{//新增任务速度
Thread.sleep(new Long(2*1000));
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}static class MyThread implementsRunnable{
@Overridepublic voidrun() {
System.out.println("thread " + Thread.currentThread().getName() + " is running for task:" + (taskId++));try{//任务线程执行所需时间
Thread.sleep(new Long(1*1000));
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
}
这种情况下,线程池只需要一个线程就够用了:
thread pool-1-thread-1 is running for task:0thread pool-1-thread-1 is running for task:1thread pool-1-thread-1 is running for task:2thread pool-1-thread-1 is running for task:3thread pool-1-thread-1 is running for task:4thread pool-1-thread-1 is running for task:5
如果把任务执行时间增加到3秒,则会产生3个线程:
thread pool-1-thread-1 is running for task:0thread pool-1-thread-2 is running for task:1thread pool-1-thread-3 is running for task:2thread pool-1-thread-1 is running for task:3thread pool-1-thread-2 is running for task:4thread pool-1-thread-3 is running for task:5thread pool-1-thread-1 is running for task:6thread pool-1-thread-2 is running for task:7thread pool-1-thread-3 is running for task:8thread pool-1-thread-1 is running for task:9
如果刚开始新增任务速度很快,后来变慢了,之前新增的线程会被回收掉:
public static voidmain(String[] args) {int i = 0;while(true) {
service.execute(newMyThread());long sleep = i>=5 ? 2000 : 50; #
Thread.sleep(sleep);
}catch(InterruptedException e) {
e.printStackTrace();
}
i++;
}
}static class MyThread implementsRunnable{
@Overridepublic voidrun() {
System.out.println("thread " + Thread.currentThread().getName() + " is running for task:" + (taskId++));try{//任务线程执行所需时间
Thread.sleep(new Long(1*1000)); #
}catch(InterruptedException e) {
e.printStackTrace();
}
}
}
输出结果如下:
thread pool-1-thread-1 is running for task:0thread pool-1-thread-2 is running for task:1thread pool-1-thread-3 is running for task:2thread pool-1-thread-4 is running for task:3thread pool-1-thread-5 is running for task:4thread pool-1-thread-6 is running for task:5thread pool-1-thread-6 is running for task:6thread pool-1-thread-6 is running for task:7thread pool-1-thread-6 is running for task:8thread pool-1-thread-6 is running for task:9thread pool-1-thread-6 is running for task:10thread pool-1-thread-6 is running for task:11thread pool-1-thread-6 is running for task:12...
后面只有thread-6在跑了,打开jconsole,会发现其他的thread-1-threac-X已经不见了。
固定大小的线程池 FixedThreadPool
这个好理解了,我就这么几个线程,你任务再多也没用。
定时执行线程池 ScheduledThreadPool
定时任务线程池要注意的是,在线程资源稀缺的时候(就是线程数量设置的很小,比增加的定时任务还少,不够用),任务的执行时间会影响任务的执行周期。简单来说就是不要把线程数量设置的太少了。
单线程的线程池 SingleThreadExecutor
它创建单个工作者来执行任务,如果工作者线程异常退出了会重新创建一个来替换。它可以确保任务在队列中依次串行执行,例如FIFO、LIFO、优先级。另外固定大小的线程池还提供了大量同步机制,从而是一个任务写入到内存的结果对于后续的任务是可见的。