Java 线程池
理论基础
在多线程处理中,有手工创建线程与线程池2种处理方式,手工创建线程存在管理与维护繁琐的问题。比如自定义线程后,使用阿里巴巴的Alibaba Java Coding Guidelines插件检查会提示错误信息“不要显示式创建线程,请使用线程池”,如下图所示:
Java通过Executors提供四种线程池,分别为:
- newCachedThreadPool( ):创建一个不限制线程数上限的的线程池,任何提交的任务都会立即执行。调用execute将重用以前创建的线程(如果线程可用)。如果没有可用的线程,则创建一个新线程并添加到池中。终止并从缓存中移出那些已有60秒钟未被使用的线程。如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收线程,则新建线程。这里的线程池是无限大的,当一个线程完成任务之后,该线程可以接下来完成将要分配的任务,而不是创建一个新的线程。
- newFixedThreadPool:创建一个固定大小的线程池,可控制线程最大并发数,超出的线程会在队列中等待。定长线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors()。
- newScheduledThreadPool(int corePoolSize):创建一个定长线程池,支持定时及周期性任务执行,多数情况下可以用来替代Time类。
- newSingleThreadExecutor( ):创建一个只有一个线程的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。newSingleThreadExecutor会按顺序来执行线程任务 但是不同于单线程,这个线程池只是只能存在一个线程,这个线程死后另外一个线程会补上。
注意:示例性质的小程序使用这些快捷方法没什么问题,对于服务端需要长期运行的程序,创建线程池应该直接使用ThreadPoolExecutor的构造法。比如阿里巴巴建议我们使用:Java线程池 之 ThreadPoolExecutor创建线程。
newCachedThreadPool public static void main(String[] args) {
ExecutorService pool = Executors.newCachedThreadPool();
for (int i = 0; i {
System.out.print(index+"*\t");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.print(index+"#\t");
});
}
pool.shutdown();
}
结果:
public static void main(String[] args) {
int size = 2; //为了看效果
//定长线程池的大小最好根据系统资源进行设置
//size = Runtime.getRuntime().availableProcessors()*2;
ExecutorService pool = Executors.newFixedThreadPool(size);
for (int i = 0; i {
System.out.print(index+"*\t");
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.print(index+"#\t");
});
}
pool.shutdown();
}
结果: 定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
public static void main(String[] args) {
ScheduledExecutorService pool = Executors.newScheduledThreadPool(3);
for (int i = 0; i System.out.print(index+"\t"),
300,
TimeUnit.MILLISECONDS
);
}
pool.shutdown();
}
结果:
public static void main(String[] args) {
ExecutorService pool = Executors.newSingleThreadExecutor();
for (int i = 0; i {
System.out.print(index + "*\t");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.print(index + "#\t");
});
}
pool.shutdown();
}
结果: 按顺序来执行线程任务 但是不同于单线程,这个线程池只能存在一个线程,线程死后另外一个线程会补上。