可以看到核心线程1个,最大线程同样也是1个,空闲等待时间为0毫秒, 即执行完本条任务后, 不继续原地等待,new LinkedBlockingQueue() 说明SingleThreadExecutor自己维护了一个链表阻塞队列, 无需手动去管理。
只有一个线程的线程池
为什么要有单线程的线程池?
- 线程池有属于自己的任务队列, 不需要自己去手动维护一个任务队列
- 有完整的生命周期管理
/**
* SingleThreadExecutor 只有一个线程的线程池
*/
public class T07_SingleThreadPool {
public static void main(String[] args) {
ExecutorService service = Executors.newSingleThreadExecutor();
for (int i = 0; i < 5; i++) {
final int j = i;
service.execute(() -> {
System.out.println(j + " " + Thread.currentThread().getName());
});
}
}
}
输出结果
0 pool-1-thread-1
1 pool-1-thread-1
2 pool-1-thread-1
3 pool-1-thread-1
4 pool-1-thread-1
固定数量线程的线程池, 构造函数只有一个参, 即线程数量
/**
* FixedThreadPool 固定线程数量的线程池
* 创建一个定长线程池,可控制线程最大并发数,超出的线程会在队列中等待
* 定长线程池的大小最好根据系统资源进行设置
*/
public class T09_FixedThreadPool {
public static void main(String[] args) throws InterruptedException, ExecutionException {
long start = System.currentTimeMillis();
//单线程执行统计1到200000之间的质数耗时
getPrime(1, 200000);
long end = System.currentTimeMillis();
System.out.println(end - start);
//根据机器CPU 核数量
final int cpuCoreNum = 4;
//使用FixedThreadPool多线程执行,统计1到200000之间的质数耗时
ExecutorService service = Executors.newFixedThreadPool(cpuCoreNum);
MyTask t1 = new MyTask(1, 80000); //1-5 5-10 10-15 15-20
MyTask t2 = new MyTask(80001, 130000);
MyTask t3 = new MyTask(130001, 170000);
MyTask t4 = new MyTask(170001, 200000);
Future<List<Integer>> f1 = service.submit(t1);
Future<List<Integer>> f2 = service.submit(t2);
Future<List<Integer>> f3 = service.submit(t3);
Future<List<Integer>> f4 = service.submit(t4);
start = System.currentTimeMillis();
f1.get();
f2.get();
f3.get();
f4.get();
end = System.currentTimeMillis();
System.out.println(end - start);
service.shutdown();
}
static class MyTask implements Callable<List<Integer>> {
//起始数, 结束数
int startPos, endPos;
MyTask(int s, int e) {
this.startPos = s;
this.endPos = e;
}
@Override
public List<Integer> call() {
//统计质数
List<Integer> r = getPrime(startPos, endPos);
return r;
}
}
static boolean isPrime(int num) {
for (int i = 2; i <= num / 2; i++) {
if (num % i == 0) {
return false;
}
}
return true;
}
static List<Integer> getPrime(int start, int end) {
List<Integer> results = new ArrayList<>();
for (int i = start; i <= end; i++) {
if (isPrime(i)) {
results.add(i);
}
}
return results;
}
}
输出结果
2002
716
这里核心线程为0, 最大线程为Integer的最大值, 基本上无限大,等待队列采用的是SynchronousQueue(),对于SynchronousQueue,每次put进入一个任务后,必须有消费者进行消费才可以继续put,如果没有消费者, 则这里就会堵塞在这里。
/**
* 创建一个可缓存线程池,如果线程池长度超过处理需要,可灵活回收空闲线程,若无可回收,则新建线程
* 线程池为无限大,当执行第二个任务时第一个任务已经完成,会复用执行第一个任务的线程,而不用每次新建线程。
*/
public class T08_CachedThreadPool {
public static void main(String[] args) throws InterruptedException {
ExecutorService service = Executors.newCachedThreadPool();
//初始化完成, 输出线程池基本信息
System.out.println(service);
for (int i = 0; i < 3; i++) {
service.execute(() -> {
try {
TimeUnit.MILLISECONDS.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName());
});
}
//打印线程池基本信息, 查看线程数, 活跃线程数, 等待队列任务数, 完成的队列任务数
System.out.println(service);
TimeUnit.SECONDS.sleep(800);
System.out.println(service);
}
}
输出结果
java.util.concurrent.ThreadPoolExecutor@60e53b93[Running, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 0]
java.util.concurrent.ThreadPoolExecutor@60e53b93[Running, pool size = 3, active threads = 3, queued tasks = 0, completed tasks = 0]
pool-1-thread-1
pool-1-thread-2
pool-1-thread-3
/**
* WorkStealingPool每个线程都有自己单独的队列, 每个线程执行完自己的任务后,
* 会去其他线程的等待队列里取出待执行的任务,去执行
*/
public class T11_WorkStealingPool {
public static void main(String[] args) throws IOException {
ExecutorService service = Executors.newWorkStealingPool();
System.out.println(Runtime.getRuntime().availableProcessors());
service.execute(new R(1000));
service.execute(new R(2000));
service.execute(new R(2000));
service.execute(new R(2000)); //daemon
service.execute(new R(2000));
//由于产生的是精灵线程(守护线程、后台线程),主线程不阻塞的话,看不到输出
System.in.read();
}
static class R implements Runnable {
int time;
R(int t) {
this.time = t;
}
@Override
public void run() {
try {
TimeUnit.MILLISECONDS.sleep(time);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(time + " " + Thread.currentThread().getName());
}
}
}
输出结果
8
1000 ForkJoinPool-1-worker-1
2000 ForkJoinPool-1-worker-3
2000 ForkJoinPool-1-worker-5
2000 ForkJoinPool-1-worker-4
2000 ForkJoinPool-1-worker-2
把大任务切分成一个个小任务来执行
/**
* 把大任务切分成一个个小任务来执行
*/
public class T12_ForkJoinPool {
static int[] nums = new int[1000000];
//设置最小任务片为5万个数
static final int MAX_NUM = 50000;
static Random r = new Random();
static {
for (int i = 0; i < nums.length; i++) {
nums[i] = r.nextInt(100);
}
System.out.println("使用Arrays.stream计算的和: " + Arrays.stream(nums).sum()); //stream api
}
/**
* 没有返回值的ForkJoin
*/
static class AddTask extends RecursiveAction {
int start, end;
AddTask(int s, int e) {
start = s;
end = e;
}
@Override
protected void compute() {
if (end - start <= MAX_NUM) {
long sum = 0L;
for (int i = start; i < end; i++) {
sum += nums[i];
}
System.out.println("from:" + start + " to:" + end + " = " + sum);
} else {
int middle = start + (end - start) / 2;
AddTask subTask1 = new AddTask(start, middle);
AddTask subTask2 = new AddTask(middle, end);
subTask1.fork();
subTask2.fork();
}
}
}
/**
* 有返回值的ForkJoin
*/
static class AddTaskReturn extends RecursiveTask<Long> {
private static final long serialVersionUID = 1L;
int start, end;
AddTaskReturn(int s, int e) {
start = s;
end = e;
}
@Override
protected Long compute() {
if (end - start <= MAX_NUM) {
long sum = 0L;
for (int i = start; i < end; i++) {
sum += nums[i];
}
return sum;
}
//取中间数
int middle = start + (end - start) / 2;
AddTaskReturn subTask1 = new AddTaskReturn(start, middle);
AddTaskReturn subTask2 = new AddTaskReturn(middle, end);
subTask1.fork();
subTask2.fork();
return subTask1.join() + subTask2.join();
}
}
public static void main(String[] args) throws IOException {
//没有返回值
// ForkJoinPool fjp = new ForkJoinPool();
// AddTask task = new AddTask(0, nums.length);
// fjp.execute(task);
// System.in.read();
//有返回值
ForkJoinPool fjp = new ForkJoinPool();
AddTaskReturn task = new AddTaskReturn(0, nums.length);
fjp.execute(task);
long result = task.join();
System.out.println("使用ForkJoinPool计算出的和: "+ result);
System.in.read();
}
}
没有返回值的输出结果
使用Arrays.stream计算的和: 49544455
from:968750 to:1000000 = 1548248
from:218750 to:250000 = 1539443
from:718750 to:750000 = 1547722
from:468750 to:500000 = 1545115
from:843750 to:875000 = 1544120
from:937500 to:968750 = 1546731
from:187500 to:218750 = 1535385
from:437500 to:468750 = 1551864
from:687500 to:718750 = 1547479
from:812500 to:843750 = 1542819
from:406250 to:437500 = 1548120
from:593750 to:625000 = 1547728
from:656250 to:687500 = 1544024
from:156250 to:187500 = 1544398
from:93750 to:125000 = 1558824
from:375000 to:406250 = 1551525
from:906250 to:937500 = 1544222
from:625000 to:656250 = 1555051
from:562500 to:593750 = 1547992
from:875000 to:906250 = 1548874
from:31250 to:62500 = 1541202
from:343750 to:375000 = 1541366
from:62500 to:93750 = 1550987
from:281250 to:312500 = 1539370
from:312500 to:343750 = 1542633
from:250000 to:281250 = 1538104
from:125000 to:156250 = 1543367
from:0 to:31250 = 1543700
from:500000 to:531250 = 1548381
from:750000 to:781250 = 1540401
from:531250 to:562500 = 1546152
from:781250 to:812500 = 1548994
有返回值
使用Arrays.stream计算的和: 49544455
使用ForkJoinPool计算出的和: 49544455
ParallelStreamAPI
/**
* 并行流处理, 底层采用ForkJoinPool实现
*/
public class ParallelStreamAPI {
public static void main(String[] args) {
List<Integer> nums = new ArrayList<>();
Random r = new Random();
for (int i = 0; i < 10000; i++) {
nums.add(1000000 + r.nextInt(1000000));
}
//System.out.println(nums);
long start = System.currentTimeMillis();
nums.forEach(v -> isPrime(v));
long end = System.currentTimeMillis();
System.out.println(end - start);
//使用parallel stream api
start = System.currentTimeMillis();
nums.parallelStream().forEach(T13_ParallelStreamAPI::isPrime);
end = System.currentTimeMillis();
System.out.println(end - start);
}
/**
* 判断是不是质数
* @param num
* @return
*/
static boolean isPrime(int num) {
for (int i = 2; i <= num / 2; i++) {
if (num % i == 0) {
return false;
}
}
return true;
}
}
阿里开发规范建议自定义线程池
/**
* 线程池的一些参数配置和介绍
*/
public class ThreadPoolTest {
static class Task implements Runnable {
private int i;
public Task(int i) {
this.i = i;
}
@Override
public void run() {
System.out.println(Thread.currentThread().getName() + " Task " + i);
try {
//模拟业务处理过程,业务执行完才会释放
// 这里阻塞住执行到这里的线程, 等待手动释放
System.in.read();
} catch (IOException e) {
e.printStackTrace();
}
}
@Override
public String toString() {
return "Task{" +
"i=" + i +
'}';
}
}
public static void main(String[] args) {
ThreadPoolExecutor tpe = new ThreadPoolExecutor(2, 4,
60, TimeUnit.SECONDS,//存活60秒内没有工作做,则将线程归还给操作系统
new ArrayBlockingQueue<Runnable>(4),//等待队列, 里面设置只能装4个任务
Executors.defaultThreadFactory(),//创建线程的线程工厂
new ThreadPoolExecutor.CallerRunsPolicy()); //当线程池中没有空闲线程,并且线程的等待队列也都满了之后, 提供的拒绝策略
// new ThreadPoolExecutor.AbortPolicy());
// new ThreadPoolExecutor.DiscardPolicy());
// new ThreadPoolExecutor.DiscardOldestPolicy()); //扔掉那个排队时间最久的
//jdk默认提供了四种拒绝策略, 也可以自定义
//这四种分别如下:
//1.AbortPolicy: 抛异常
//2.DiscardPolicy:扔掉, 不抛异常
//3.DiscardOldestPolicy: 扔掉排队时间最久的
//4.CallerRunsPolicy: 调用者处理任务: 哪个线程发起的任务, 哪个线程去处理它
for (int i = 0; i < 8; i++) {
tpe.execute(new Task(i));
}
//输出等待队列, 由于设置的最大线程数为4个, 所以第一次执行完毕后,
//等待队里里会有8-4=4个线程
System.out.println("第一次等待队列: " + tpe.getQueue());
//再次执行一条任务
tpe.execute(new Task(100));
//再次输出
System.out.println("第二次等待队列: " + tpe.getQueue());
tpe.shutdown();
}
}
输出结果
pool-1-thread-2 Task 1
pool-1-thread-4 Task 7
pool-1-thread-3 Task 6
pool-1-thread-1 Task 0
第一次等待队列: [Task{i=2}, Task{i=3}, Task{i=4}, Task{i=5}]
main Task 100
1
pool-1-thread-2 Task 2
第二次等待队列: [Task{i=3}, Task{i=4}, Task{i=5}]
1
pool-1-thread-1 Task 3
pool-1-thread-3 Task 4
1
pool-1-thread-4 Task 5
1
1