Java四种线程池的示例
Java通过Executors提供四种线程池,分别为:
newCachedThreadPool创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。
newFixedThreadPool 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。
newScheduledThreadPool 创建一个定长线程池,支持定时及周期性任务执行。
newSingleThreadExecutor 创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。
(1) newCachedThreadPool
创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程。示例代码如下:
- package test;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- public class ThreadPoolExecutorTest {
- public static void main(String[] args) {
- ExecutorService cachedThreadPool = Executors.newCachedThreadPool();
- for (int i = 0; i < 10; i++) {
- final int index = i;
- try {
- Thread.sleep(index * 1000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- cachedThreadPool.execute(new Runnable() {
- public void run() {
- System.out.println(index);
- }
- });
- }
- }
- }
线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。
(2) newFixedThreadPool
创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待。示例代码如下:
- package test;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- public class ThreadPoolExecutorTest {
- public static void main(String[] args) {
- ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
- for (int i = 0; i < 10; i++) {
- final int index = i;
- fixedThreadPool.execute(new Runnable() {
- public void run() {
- try {
- System.out.println(index);
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- });
- }
- }
- }
因为线程池大小为3,每个任务输出index后sleep 2秒,所以每两秒打印3个数字。
定长线程池的大小最好根据系统资源进行设置。如Runtime.getRuntime().availableProcessors()
(3) newScheduledThreadPool
创建一个定长线程池,支持定时及周期性任务执行。延迟执行示例代码如下:
- package test;
- import java.util.concurrent.Executors;
- import java.util.concurrent.ScheduledExecutorService;
- import java.util.concurrent.TimeUnit;
- public class ThreadPoolExecutorTest {
- public static void main(String[] args) {
- ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
- scheduledThreadPool.schedule(new Runnable() {
- public void run() {
- System.out.println("delay 3 seconds");
- }
- }, 3, TimeUnit.SECONDS);
- }
- }
表示延迟3秒执行。
定期执行示例代码如下:
- package test;
- import java.util.concurrent.Executors;
- import java.util.concurrent.ScheduledExecutorService;
- import java.util.concurrent.TimeUnit;
- public class ThreadPoolExecutorTest {
- public static void main(String[] args) {
- ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(5);
- scheduledThreadPool.scheduleAtFixedRate(new Runnable() {
- public void run() {
- System.out.println("delay 1 seconds, and excute every 3 seconds");
- }
- }, 1, 3, TimeUnit.SECONDS);
- }
- }
表示延迟1秒后每3秒执行一次。
(4) newSingleThreadExecutor
创建一个单线程化的线程池,它只会用唯一的工作线程来执行任务,保证所有任务按照指定顺序(FIFO, LIFO, 优先级)执行。示例代码如下:
- package test;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- public class ThreadPoolExecutorTest {
- public static void main(String[] args) {
- ExecutorService singleThreadExecutor = Executors.newSingleThreadExecutor();
- for (int i = 0; i < 10; i++) {
- final int index = i;
- singleThreadExecutor.execute(new Runnable() {
- public void run() {
- try {
- System.out.println(index);
- Thread.sleep(2000);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- });
- }
- }
- }
结果依次输出,相当于顺序执行各个任务。
你可以使用JDK自带的监控工具来监控我们创建的线程数量,运行一个不终止的线程,创建指定量的线程,来观察:
工具目录:C:\Program Files\Java\jdk1.6.0_06\bin\jconsole.exe
运行程序做稍微修改:
- package test;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- public class ThreadPoolExecutorTest {
- public static void main(String[] args) {
- ExecutorService singleThreadExecutor = Executors.newCachedThreadPool();
- for (int i = 0; i < 100; i++) {
- final int index = i;
- singleThreadExecutor.execute(new Runnable() {
- public void run() {
- try {
- while(true) {
- System.out.println(index);
- Thread.sleep(10 * 1000);
- }
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- });
- try {
- Thread.sleep(500);
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- }
- }
效果如下:
选择我们运行的程序:
监控运行状态
四大线程池 https://blog.****.net/qq_26963495/article/details/79056391
本文讲述之前我们提到的Executors类(注意加了s的)中的六个静态方法,分别创建六种不同的线程池对象。之前我们已经提到,ThreadPoolExecutor类的别称就是线程池。它是继承自Executor接口(注意没有s)。继承关系图如下。
六大静态方法创建的ThreadPoolExecutor对象,返回的父接口的引用,即返回的ExecutorService的引用。六大静态方法内部都是直接或间接调用ThreadPoolExecutor类的构造方法创建线程池对象,这六个静态方法本身是没有技术含量的。其中一个静态方法的源码如下,其他5个也类似。
①:FixedThreadPool,特点:固定池子中线程的个数。使用静态方法newFixedThreadPool()创建线程池的时候指定线程池个数。示例如下:
输出如下:
②:CachedThreadPool(弹性缓存线程池),特点:用newCachedThreadPool()方法创建该线程池对象,创建之初里面一个线程都没有,当execute方法或submit方法向线程池提交任务时,会自动新建线程;如果线程池中有空余线程,则不会新建;这种线程池一般最多情况可以容纳几万个线程,里面的线程空余60s会被回收。创建示例:
③:SingleThreadPool(单线程线程池),特点:池中只有一个线程,如果扔5个任务进来,那么有4个任务将排队;作用是保证任务的顺序执行。创建示例:
④:ScheduledThreadpool(定时器线程池),这种线程池的创建,对应的静态方法为:
返回的不再是ExecutorService接口的引用了,但是我们依然可以用ExecutorService接口的引用去引用这种线程池对象。因为返回的是ScheduledExecutorService接口的引用,这个接口也是继承自ExecutorService接口,源码如下:
同时我们看到在newScheduledThreadPool方法中也不再是调用ThreadPoolExecutor类的构造方法,而是调的ScheduledThreadPoolExecutor这个方法,这个方法是ScheduledThreadPoolExecutor类的构造方法。这个类和之前我们提到的线程池类的(继承)关系如下:
在子类ScheduledThreadPoolExecutor构造方法中是直接调用的父类构造方法,于是归根结底还是调用的ThreadPoolExecutor类的构造方法。
整理上面几个接口和类的关系如下:
源码中ScheduledThreadPoolExecutor类的定义如下:
由上面整理的继承关系图可知,我们使用那三个接口的引用去引用这种线程池对象都是可以的(但是在使用时,切记只能用下面的第三种引用方式,因为虽然创建的是ScheduledThreadPoolExecutor对象,但如果用Executor去引用,就只能调用Executor接口中定义的方法;如果用ExecutorService接口去引用,就只能调用ExecutorService接口中定义的方法,无法使用ScheduledExecutorService接口中新增的方法,那么也就失去了这种线程池的意义),在idea中演示如下:
自此,我们明白了这种线程池和之前提到的接口和之前使用的线程池的关系,以及这种线程池的创建和引用方法。
接下来我们讲述这种线程池的使用方法,主要是使用ScheduledExecutorService接口中新增的方法。例如cheduleAtFixedRate()方法,方法签名如下:
接收4个参数,从形参名我们应该就能猜出来四个参数的含义了。第一个参数:接收一个Runnable任务。第二个参数:初始延迟时间,任务提交到线程池后延迟这么多时间才开始执行,如果设为0,那就是任务提交过来就开始执行了。第三个参数:这个任务会每隔这么多时间重新执行一次。第四个参数:为前两个参数的单位。使用示例如下:
除了cheduleAtFixedRate()方法,还有scheduleWithFixedDelay()方法和schedule()方法。本文不再赘述,在此基础上,读者可以查看源码注释。