一、Thread与Executors
开启新的线程,我们经常会采用如下方法:
Thread thread =new Thread(new Runnable() {
@Override
public void run() {
System.out.println("new thread");
}
});
通过new Thread()的方式,会导致很多弊端,如下:
- 每一次都通过new Thread的方式,性能差。
- 线程缺乏统一管理,可能无限制新建线程,相互之间竞争,及可能占用过多系统资源导致宕机。
- 缺乏定时执行、定期执行、线程中断等功能。
Executors提供的四种线程池有效的解决以上问题
二、Executors提供的四种线程池
- newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
- newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
- newScheduledThreadPool 创建一个定长线程池,同时支持定时及周期性任务执行。
- newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序执行。
三、newCachedThreadPool
ExecutorService executorService1 = Executors.newCachedThreadPool();
Future<String> future = executorService1.submit(new Callable<String>() { @Override
public String call() throws Exception {
return "newCachedThreadPool";
}
});
try {
System.out.println(future.get());
} catch (Exception e) {
e.printStackTrace();
}
四、newFixedThreadPool
ExecutorService executorService2 = Executors.newFixedThreadPool(3);//定长3个线程
for (int i = 0; i < 10; i++) {
executorService2.execute(new Runnable() {//execute与submit的区别
@Override
public void run() {
try {
System.out.println("定长三个线程");
TimeUnit.SECONDS.sleep(3);//注意和Thread.sleep(3000)的区别
} catch (InterruptedException e) {
System.out.println("InterruptedException");
} catch (Exception e) {
System.out.println("Exception");
}
}
});
}
每隔三秒钟,打印三条数据
五、newScheduledThreadPool
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);//定长三个线程
scheduledThreadPool.schedule(new Runnable() {
@Override
public void run() {
System.out.println("延迟三秒输出");
}
}, 3, TimeUnit.SECONDS);
延迟三秒输出
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);//定长三个线程
scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
System.out.println("延迟1秒,然后定期每三秒执行一次");
}
},1, 3, TimeUnit.SECONDS);
延迟一秒,然后定期执行
六、newSingleThreadExecutor
ExecutorService executorService4 = Executors.newSingleThreadExecutor();
for (int i = 1; i < 11; i++) {
//所有被内部类访问的局部变量,都必须使用final修饰
//对于普通局部变量而言,当方法结束以后,该局部变量也就随之消失
//但是匿名内部类的生命周期没有结束的话,将一直可以访问局部变量的值,内部类会扩大局部变量的作用域,会引发混乱
final int index = i;
executorService4.execute(new Runnable() {
@Override
public void run() {
System.out.println("Thread:" + index);
}
});
}
七、其他知识点
7.1、submit与execute的区别
- submit支持Callable,execute支持Runable
- submit有返回值,execute无返回值
- submit可以捕获异常(还是因为支持Callable),execute不可以
7.2、shutdown与shutdownNow的区别
- shutdown()方法在终止前允许执行正在进行的线程
- shutdownNow()方法阻止新的进程并试图停止当前正在执行的线程,关闭未使用的 ExecutorService 以允许回收其资源。