Executors如何创建线程池?

Executors 类是从 JDK 1.5 开始就新增的线程池创建的静态工厂类,它就是创建线程池的,但是很多的大厂已经不建议使用该类去创建线程池。原因在于,该类创建的很多线程池的内部使用了***任务队列,在并发量很大的情况下会导致 JVM 抛出 OutOfMemoryError,直接让 JVM 崩溃,影响严重。

 

但是 Executors 类究竟是如何使用的?

1. newFixedThreadPool,创建定长线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大数量,这时线程数量不再变化,当线程发生错误结束时,线程池会补充一个新的线程。

package constxiong.concurrency.a011;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
* 测试创建定长线程池
* @author ConstXiong
*/

public class TestNewFixedThreadPool {

public static void main(String[] args) {
//创建工作线程数为 3 的线程池,每当提交一个任务就创建一个线程,直到达到线程池的最大数量,这时线程数量不再变化,当线程发生错误结束时,线程池会补充一个新的线程
ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
//提交 6 个任务
for (int i = 0; i < 6; i++) {
final int index = i;
fixedThreadPool.execute(() -> {
try {
//休眠 3 秒
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " index:" + index);
});
}

try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("4秒后...");

//关闭线程池后,已提交的任务仍然会执行完
fixedThreadPool.shutdown();
}

}

打印结果:

pool-1-thread-2 index:1
pool-1-thread-3 index:2
pool-1-thread-1 index:0
4秒后...
pool-1-thread-1 index:4
pool-1-thread-3 index:5
pool-1-thread-2 index:3

 

2. newCachedThreadPool,创建可缓存的线程池,如果线程池的容量超过了任务数,自动回收空闲线程,任务增加时可以自动添加新线程,线程池的容量不限制。

package constxiong.concurrency.a011;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
* 测试创建可缓存的线程池
* @author ConstXiong
*/

public class TestNewCachedThreadPool {

public static void main(String[] args) {
//创建可缓存的线程池,如果线程池的容量超过了任务数,自动回收空闲线程,任务增加时可以自动添加新线程,线程池的容量不限制
ExecutorService cachedThreadPool = Executors.newCachedThreadPool();

for (int i = 0; i < 6; i++) {
final int index = i;
cachedThreadPool.execute(() -> {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " index:" + index);
});
}

try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("4秒后...");

cachedThreadPool.shutdown();

}

}

打印结果可以看出,创建的线程数任务数相等

pool-1-thread-1 index:0
pool-1-thread-3 index:2
pool-1-thread-6 index:5
pool-1-thread-4 index:3
pool-1-thread-5 index:4
pool-1-thread-2 index:1
4秒后...

 

3. newScheduledThreadPool,创建定长线程池,可执行周期性的任务。

package constxiong.concurrency.a011;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
* 测试创建定长线程池,可执行周期性的任务
* @author ConstXiong
*/

public class TestNewScheduledThreadPool {

public static void main(String[] args) {
//创建定长线程池,可执行周期性的任务
ScheduledExecutorService scheduledThreadPool = Executors.newScheduledThreadPool(3);

for (int i = 0; i < 3; i++) {
final int index = i;
//scheduleWithFixedDelay 固定的延迟时间执行任务;scheduleAtFixedRate 固定的频率执行任务
scheduledThreadPool.scheduleWithFixedDelay(() -> {
System.out.println(Thread.currentThread().getName() + " index:" + index);
}, 0, 3, TimeUnit.SECONDS);
}

try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("4秒后...");

scheduledThreadPool.shutdown();

}
}

打印结果:

pool-1-thread-1 index:0
pool-1-thread-3 index:2
pool-1-thread-2 index:1
pool-1-thread-1 index:0
pool-1-thread-2 index:1
pool-1-thread-3 index:2
4秒后...

 

4. newSingleThreadExecutor,创建单线程的线程池,线程异常结束,会创建一个新的线程,能确保任务按提交顺序执行。

package constxiong.concurrency.a011;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
* 测试单线程的线程池
* @author ConstXiong
*/

public class TestNewSingleThreadExecutor {

public static void main(String[] args) {
//单线程的线程池,线程异常结束,会创建一个新的线程,能确保任务按提交顺序执行
ExecutorService singleThreadPool = Executors.newSingleThreadExecutor();

//提交 3 个任务
for (int i = 0; i < 3; i++) {
final int index = i;
singleThreadPool.execute(() -> {

//执行第二个任务时,报错,测试线程池会创建新的线程执行任务三
if (index == 1) {
throw new RuntimeException("线程执行出现异常");
}

try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " index:" + index);
});
}

try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("4秒后...");

singleThreadPool.shutdown();
}

}

打印结果可以看出,即使任务出现了异常,线程池还是会自动补充一个线程继续执行下面的任务

pool-1-thread-1 index:0
Exception in thread "pool-1-thread-1"
java.lang.RuntimeException: 线程执行出现异常
at constxiong.concurrency.a011.TestNewSingleThreadExecutor.lambda$0(TestNewSingleThreadExecutor.java:21)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)
at java.lang.Thread.run(Thread.java:748)
4秒后...
pool-1-thread-2 index:2

 

5. newSingleThreadScheduledExecutor,创建单线程可执行周期性任务的线程池。

package constxiong.concurrency.a011;

import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;

/**
* 测试单线程可执行周期性任务的线程池
* @author ConstXiong
*/

public class TestNewSingleThreadScheduledExecutor {

public static void main(String[] args) {
//创建单线程可执行周期性任务的线程池
ScheduledExecutorService singleScheduledThreadPool = Executors.newSingleThreadScheduledExecutor();

//提交 3 个固定频率执行的任务
for (int i = 0; i < 3; i++) {
final int index = i;
//scheduleWithFixedDelay 固定的延迟时间执行任务;scheduleAtFixedRate 固定的频率执行任务
singleScheduledThreadPool.scheduleAtFixedRate(() -> {
System.out.println(Thread.currentThread().getName() + " index:" + index);
}, 0, 3, TimeUnit.SECONDS);
}

try {
Thread.sleep(4000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("4秒后...");

singleScheduledThreadPool.shutdown();
}

}

打印机结果可以看出 0-2 任务都被执行了 2 个周期

pool-1-thread-1 index:0
pool-1-thread-1 index:1
pool-1-thread-1 index:2
pool-1-thread-1 index:0
pool-1-thread-1 index:1
pool-1-thread-1 index:2
4秒后...

 

6. newWorkStealingPool,创建任务可窃取线程池,空闲线程可以窃取其他任务队列的任务,不保证执行顺序,适合任务耗时差异较大。

package constxiong.concurrency.a011;

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
* 测试可任务窃取线程池
* @author ConstXiong
*/

public class TestNewWorkStealingPool {

public static void main(String[] args) {
//创建 4个工作线程的 任务可窃取线程池,如果不设置并行数,默认取 CPU 总核数
ExecutorService workStealingThreadPool = Executors.newWorkStealingPool(4);

for (int i = 0; i < 10; i++) {
final int index = i;
workStealingThreadPool.execute(() -> {
try {
//模拟任务执行时间为 任务编号为0 1 2 的执行时间需要 3秒;其余任务200 毫秒,导致任务时间差异较大
if (index <= 2) {
Thread.sleep(3000);
} else {
Thread.sleep(200);
}
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + " index:" + index);
});
}

try {
Thread.sleep(10000);//休眠 10 秒
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("10秒后...");
}

}

打印结果可以看出,线程 ForkJoinPool-1-worker-0 把3-9的任务都执行完

ForkJoinPool-1-worker-0 index:3
ForkJoinPool-1-worker-0 index:4
ForkJoinPool-1-worker-0 index:5
ForkJoinPool-1-worker-0 index:6
ForkJoinPool-1-worker-0 index:7
ForkJoinPool-1-worker-0 index:8
ForkJoinPool-1-worker-0 index:9
ForkJoinPool-1-worker-1 index:0
ForkJoinPool-1-worker-3 index:2
ForkJoinPool-1-worker-2 index:1
10秒后...

 


更多相关文章

  1. 什么是线程池?
  2. 线程包括哪些状态?状态之间是如何转变的?
  3. 什么是守护线程?
  4. 如何优雅地停止一个线程?
  5. java多线程(11)AtomicBoolean原子类分析
  6. Java基础系列:线程同步和线程池
  7. java多线程(6)sleep和wait的4大区别
  8. java多线程(5)多线程通信出现的假死现象分析
  9. java多线程(4)使用wait/notify机制进行单线程之间的通信

随机推荐

  1. 关于mysql无法添加中文数据的问题以及解
  2. MySQL学习笔记_时间,多表更新,数据库元数据
  3. 如何在MYSQL中选择下面的项目和上面的项
  4. web项目异常A web application registere
  5. centos设置mysql root密码
  6. MySQLWorkbench 创建E-R图步骤
  7. 按多列排序行选择
  8. mysql中插入中文时显示乱码
  9. org.hibernate.hql.internal.ast.QuerySy
  10. mysql数据库连接查询