在开发中我们经常与会遇到需要在子线程中处理相关操作的问题,但是遇到大量线程的时候,每次都去创建一个线程是非常不合理的做法,这里我们就需要对线程作统一的管理。也就是线程池。
一,newCachedThreadPool 可缓冲线程池,这种线程池最大数是Integer.MAX_VALUE,它的特点就是线程可以重复利用。上一个线程执行完毕之后,接下来的线程可以重复使用,不必要去重新创建。
public class Main2 {
private static int index;
public static void main(String[] args) throws ExecutionException, InterruptedException {
//创建一个可缓存的线程池,这种线程池的特点就是可以灵活的回收,复用闲置线程,但是一旦超过了最大线程数就会异常
startCachedThread();
}
public static void startCachedThread() throws ExecutionException, InterruptedException {
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
/**
* 这个是源码创建,0是核心线程数, Integer.MAX_VALUE是最大的线程数,可以理解为没有最大限制的线程数 60L是闲置时间,TimeUnit.SECONDS是单位,
* 其实也就是说在60秒之后这个闲置线程没有任务就会被shutdown
* public static ExecutorService newCachedThreadPool() {
* return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
* 60L, TimeUnit.SECONDS,
* new SynchronousQueue<Runnable>());
* }
*/
for (int i = 0; i < 10; i++) {
cachedThreadPool.execute(new task());
//执行完一个线程停顿10毫秒开启下一个线程
Thread.sleep(10);
}
//申请关闭线程执行器,这里是关闭所有正在执行的线程
List<Runnable> list = cachedThreadPool.shutdownNow();
//cachedThreadPool.submit(new task()); 使用submit提交的任务有返回值
//cachedThreadPool.shutdown(); 使用这个是指关闭不在接收新的submit的提交新线程
}
static class task implements Runnable {
@Override
public void run() {
try {
System.out.println("线程: "+Thread.currentThread()+" 正在计算");
//TimeUnit.SECONDS.sleep(5); 这种方法是可以选择时间单位的
Thread.sleep(20);//这里模拟线程执行的时间
} catch (InterruptedException e) {
// e.printStackTrace();
}
}
}
}
从以上分析可以得到的结论是,线程在重复的使用的,当没有空闲的线程的时候会重新创建新的线程
newFixedThreadPool线程池
首先介绍一下这种线程的特点,这种线程在初始化的时候就指定了数目它不会自动的关闭除非显示的去关闭。这种线程有以下特点:
- 初始化指定线程大小
- 当请求的线程大于这个数目,那么其他的线程将会在外面等待,直到前面的线程完成之后才会继续执行
- 如何其中有任何一个线程停止后将会创建一个新的线程来代替
- 这个线程池中的线程会一直保存着,直到用户显示的调用关闭线程的方法
public class Main4 {
public static void main(String[] args) {
ExecutorService fixedService2 = Executors.newFixedThreadPool(5);
/**
* 从源码上看创建的核心线程数和最大线程数都是一样的,核心线程会一直存在,直到显示的被关闭,源码中的0l,表示的就是永远不会关闭
* return new ThreadPoolExecutor(nThreads, nThreads,
* 0L, TimeUnit.MILLISECONDS,
* new LinkedBlockingQueue<Runnable>());
*/
for (int i=0;i<10;i++){
fixedService2.execute(new MyThread(i));
}
}
static class MyThread implements Runnable{
public int index;
public MyThread(int index) {
this.index = index;
}
@Override
public void run() {
System.out.println(" 线程--"+Thread.currentThread().getName()+ ""+index);
try {
TimeUnit.SECONDS.sleep(2);
}catch (Exception e){
e.printStackTrace();
}
}
}
}
newScheduledThreadPool
首先介绍下这种线程池,这种线程池的特点是定时执行的
从下面的代码中我们可以看到的是在0线程中2秒后开始执行,以后每隔2秒执行一次,1线程3秒后开始执行,以后每隔3秒执行一次,下面有打印的效果图
public static void main(String[] args) {
System.out.println( " " + getDateStr() + " start ");
ScheduledExecutorService scheduledService3 = Executors.newScheduledThreadPool(1);
scheduledService3.scheduleAtFixedRate(new MyThread(0), 2, 2, TimeUnit.SECONDS);
scheduledService3.scheduleAtFixedRate(new MyThread(1), 3, 3, TimeUnit.SECONDS);
}
public static class MyThread implements Runnable {
public int index;
public MyThread (int index) {
this.index = index;
}
@Override
public void run() {
System.out.println(index + " " + getDateStr() + " Thread-" + Thread.currentThread().getName() + " ");
}
}
public static String getDateStr() {
Date date = new Date();
SimpleDateFormat sdf = new SimpleDateFormat("HH:mm:ss");
return sdf.format(date);
}
SingleThreadExecutor
这种线程可以参考前面的 newFixedThreadPool 这种线程池,这里的线程池实际上就是核心线程为1的线程池,超过1的线程数量都会在外面等待。