在生产环境中,为每一个任务分配一个线程,尤其是在大量创建线程的时候是由一定缺陷的:
线程生命周期的开销非常高。线程的创建与销毁需要JVM和操作系统提供一些辅助操作,如果请求率非常高,那么为每个请求创建一个新线程将消耗大量的计算资源。
资源消耗高。活跃的线程会消耗大量的内存资源。
稳定性差。线程过多可能抛出OutOfMemoryError异常。
Executor 和 Executors
Executor是提供一种将任务提交与每个任务将如何运行的机制(包括线程使用的细节、调度等)分离开来的方法。通常使用Executor来创建线程,而不是使用new Thread显示的创建线程。
Executors可以理解为Executor的工厂类。提供了创建Executor类型的工厂方法。
程序一:为每一个任务创建一个线程
public class AsynExecutor implements Executor{
@Override
public void execute(Runnable command) {
new Thread(command).start();
}
public static void main(String[] args) {
AsynExecutor ae = new AsynExecutor();
for(int i=0;i<5;i++) {
ae.execute(new MyRunnable(""+i));
}
}
}
public class MyRunnable implements Runnable {
String name ;
public MyRunnable(String name) {
this.name = name;
}
@Override
public void run() {
System.out.println(name + " 执行任务");
}
}
程序二:顺序执行任务
public class SynExecutor implements Executor{
@Override
public void execute(Runnable command) {
command.run();
}
public static void main(String[] args) {
SynExecutor se = new SynExecutor();
for(int i=0;i<5;i++) {
se.execute(new MyRunnable(""+i));
}
}
}
Executor 生命周期
Executor扩展了ExecutorService接口,添加了一些用于管理生命周期的方法与便于任务提交的方法。
ExecutorService的状体分为运行、关闭和终止。在初始创建时处于运行状态。shutdown方法将执行平缓的的关闭过程,启动一次顺序关闭,执行以前提交的任务,但不接受新任务;shutdownNow方法执行粗暴的关闭过程,试图停止所有正在执行的活动任务,暂停处理正在等待的任务,并返回等待执行的任务列表。
程序三:Executor的生命周期
public class ExecutorLifeCycle {
static volatile int i=0;
public static void main(String[] args) {
ExecutorService es = Executors.newFixedThreadPool(3);
es.execute(new Runnable() {
@Override
public void run() {
while(true) {
if(i == 2) {
es.shutdown();
System.out.println("执行关闭的动作");
break;
}
}
}
});
for(i=0;i<3;i++) {
try {
Thread.sleep(400);
if(!es.isShutdown()) {
System.out.println("加入到es的线程i = "+i);
es.execute(new MyRunnable("加入的线程:"+i));
}
} catch (InterruptedException e1) {
e1.printStackTrace();
}
}
}
}
如果ExecutorService不关闭,程序将不会退出
![](https://i-blog.csdnimg.cn/blog_migrate/87112943bc6e6e4429f80a16fa60ffd7.webp?x-image-process=image/format,png)