java中的两类线程池
1、ThreadPoolExecutor类线程池,下面专门用一个类来介绍
package com.lyzx.concurrent.threadPool;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.*;
/**
* 这个类介绍和测试java自带的线程池,包括
* 1、FixedThreadPool
* 2、newCachedThreadPool
* 3、SingleThreadExecutor
* 4、ScheduledThreadPool
*/
public class PoolTest {
private static Runnable r1= ()->{
for(int i=0;i<10;i++){
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"::"+i);
}
};
private static Callable c1 = ()->{
long result = 0;
for(int i=1;i<=100;i++){
result+= i;
}
return result;
};
/**
* 测试FixedThreadPool和shutdown()以及isTerminated
* newFixedThreadPool的特点有固定的大小
* 大小不可扩展,默认的生命周期为无限即要么虚拟机关闭,要么调用shutdown()方法
* 否则线程池一直活着
* 使用场景:一般情况下使用线程池的首选
其构造器如下:nThreads表示核心线程数和最大线程数一样多,也就是线程数是固定的,
0L表示线程空闲多少时间就销毁,0表示永远不会销毁,使用LinkedBlockingQueue来持有线程,这
种阻塞队列吞吐量比较大
public static ExecutorService newFixedThreadPool(int nThreads) {
return new ThreadPoolExecutor(nThreads, nThreads,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue());
}
*/
@Test
public void test1(){
Runnable[] arr = new Runnable[10];
Arrays.fill(arr,r1);
ExecutorService p1 = Executors.newFixedThreadPool(5);
System.out.println("p1.isShutdown():"+p1.isShutdown()+" p1.isTerminated():"+p1.isTerminated());
for(Runnable r : arr){
p1.submit(r);
}
p1.shutdown();
System.out.println("p1.isShutdown():"+p1.isShutdown()+" p1.isTerminated():"+p1.isTerminated());
try {
Thread.sleep(2000);
}catch(InterruptedException e){
e.printStackTrace();
}
System.out.println("p1.isShutdown():"+p1.isShutdown()+" p1.isTerminated():"+p1.isTerminated());
}
/**
*测试newCachedThreadPool和submit()
* newCachedThreadPool 容量无限大,只要当前的线程不能满足任务的处理
* 就扩容,当任务执行完毕后,形成空闲时间达到60s就自动kill掉线程
* 使用场景:在机器空闲时,处理并发高低差别很大的时候,比如并发低的时候1s不到1条请求,
* 而并发高的时候1s有1w+的请求就适合使用这种线程池
*
* Future代表未来,就是说当任务被提交(submit)后不会阻塞,而是返回一个未来对象
* 可以通过其get()方法获取Callable的返回值,当然get()方法时阻塞的
其构造方法如下,表示刚开始核心的线程数为0,无限创造线程,如果某个线程空闲60s就销毁,使用
SynchronousQueue来持有Runnable任务
public static ExecutorService newCachedThreadPool() {
return new ThreadPoolExecutor(0, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS,
new SynchronousQueue());
}
*/
@Test
public void test2(){
ExecutorService p1 = Executors.newCachedThreadPool();
Callable[] arr = new Callable[5];
Arrays.fill(arr,c1);
List futures = new ArrayList<>();
for(Callable c : arr){
Future f = p1.submit(c);
futures.add(f);
}
long result = 0;
for(Future f: futures){
try {
Long l = f.get();
result+=l;
} catch (InterruptedException e) {
e.printStackTrace();
} catch (ExecutionException e) {
e.printStackTrace();
}
}
System.out.println("result::"+result);
}
/**
* 测试SingleThreadExecutor 一个线程池里只有一个线程
* 使用场景:保证任务顺序,比如多人聊天室里面的公告,发送一个公告可以由一个线程执行以确保公告
的有序执行
构造方法如下:
表示只有一个线程工作,永远不会失效,使用LinkedBlockingQueue持有Runnable任务
public static ExecutorService newSingleThreadExecutor() {
return new FinalizableDelegatedExecutorService
(new ThreadPoolExecutor(1, 1,
0L, TimeUnit.MILLISECONDS,
new LinkedBlockingQueue()));
}
*/
@Test
public void test3(){
System.out.println("=============");
ExecutorService p1 = Executors.newSingleThreadExecutor();
Runnable[] arr = new Runnable[10];
Arrays.fill(arr,r1);
for(Runnable r :arr){
p1.execute(r);
}
try {
Thread.sleep(Integer.MAX_VALUE);
}catch(InterruptedException e){
e.printStackTrace();
}
}
/**
* 测试ScheduledThreadPool,用于任务调度
* 可以定时执行
*/
@Test
public void test4(){
ScheduledExecutorService p1 = Executors.newScheduledThreadPool(5);
//延迟2秒执行r1 只执行一次
// p1.schedule(r1,2,TimeUnit.SECONDS);
/**
package com.lyzx.concurrent.threadPool;
import java.util.concurrent.*;
/**
* 分支合并线程池(mapReduce 类似的设计思想)。适合用于处理复杂任务。
* 初始化线程容量与 CPU 核心数相关。
* 线程池中运行的内容必须是 ForkJoinTask 的子类型(RecursiveTask,RecursiveAction)。
* ForkJoinPool - 分支合并线程池。 可以递归完成复杂任务。 要求可分支合并的任务必须
* 是 ForkJoinTask 类型的子类型。 其中提供了分支和合并的能力。 ForkJoinTask 类型提供了两个
* 抽象子类型, RecursiveTask 有返回结果的分支合并任务,RecursiveAction 无返回结果的分支合并任务。(
* Callable/Runnable) compute 方法:就是任务的执行逻辑。
* ForkJoinPool 没有所谓的容量。默认都是 1 个线程。根据任务自动的分支新的子线程。
* 当子线程任务结束后,自动合并。 所谓自动是根据 fork 和 join 两个方法实现的。
* 应用: 主要是做科学计算或天文计算的。 数据分析的。
*/
public class ForkJoinPoolTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
long[] arr = new long[20000];
for(int i=0;i future = pool.submit(task);
System.out.println(future.get());
}
}
class JoinTask extends RecursiveTask{
private int start,end;
private long[] arr;
private int target;
public JoinTask(long[] arr,int start,int end,int target){
this.arr = arr;
this.start = start;
this.end = end;
this.target = target;
}
@Override
protected Long compute() {
/**
* 如果分配的数组大小达到了指定的大小就执行相加的操作
* 否则就继续拆分
*/
if(end - start <= target){
Long result = 0L;
for(int i=start;i
* 按照固定的频率,没1秒钟执行一次 * 如果Runnable执行的时间 t>period,虽然是多线程但也是阻塞式的执行, * 所以尽量避免t>period的情况发生 */ p1.scheduleAtFixedRate(()->{ System.out.println(Thread.currentThread().getName()+" 开始:: "+System.currentTimeMillis()); try { TimeUnit.SECONDS.sleep(5); } catch (InterruptedException e) { e.printStackTrace(); } System.out.println(Thread.currentThread().getName()+" 结束:: "+System.currentTimeMillis()); },0,1,TimeUnit.SECONDS);// p1.shutdown(); try{ Thread.sleep(Integer.MAX_VALUE); }catch(InterruptedException e){ e.printStackTrace(); } } public static void main(String[] args){ ScheduledExecutorService p1 = Executors.newScheduledThreadPool(5); p1.scheduleAtFixedRate(r1,2000,500,TimeUnit.MILLISECONDS);// p1.shutdown(); // 定时完成任务。 scheduleAtFixedRate(Runnable, start_limit, limit, timeunit) // runnable - 要执行的任务。// p1.scheduleAtFixedRate(r1, 0, 500, TimeUnit.MILLISECONDS); }}
2、ForkJoin线程池
package com.lyzx.concurrent.threadPool;
import java.util.concurrent.*;
/**
* 分支合并线程池(mapReduce 类似的设计思想)。适合用于处理复杂任务。
* 初始化线程容量与 CPU 核心数相关。
* 线程池中运行的内容必须是 ForkJoinTask 的子类型(RecursiveTask,RecursiveAction)。
* ForkJoinPool - 分支合并线程池。 可以递归完成复杂任务。 要求可分支合并的任务必须
* 是 ForkJoinTask 类型的子类型。 其中提供了分支和合并的能力。 ForkJoinTask 类型提供了两个
* 抽象子类型, RecursiveTask 有返回结果的分支合并任务,RecursiveAction 无返回结果的分支合并任务。(
* Callable/Runnable) compute 方法:就是任务的执行逻辑。
* ForkJoinPool 没有所谓的容量。默认都是 1 个线程。根据任务自动的分支新的子线程。
* 当子线程任务结束后,自动合并。 所谓自动是根据 fork 和 join 两个方法实现的。
* 应用: 主要是做科学计算或天文计算的。 数据分析的。
*/
public class ForkJoinPoolTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
long[] arr = new long[20000];
for(int i=0;i future = pool.submit(task);
System.out.println(future.get());
}
}
class JoinTask extends RecursiveTask{
private int start,end;
private long[] arr;
private int target;
public JoinTask(long[] arr,int start,int end,int target){
this.arr = arr;
this.start = start;
this.end = end;
this.target = target;
}
@Override
protected Long compute() {
/**
* 如果分配的数组大小达到了指定的大小就执行相加的操作
* 否则就继续拆分
*/
if(end - start <= target){
Long result = 0L;
for(int i=start;i
3、线程池的原理
3.1、FixedThreadPool
固定大小的线程池,即最核心的线程数和最大的线程数一样大,所以该不能扩容,
另外其使用LinkedBlockingQueue ,会把大于线程数的任务放入这个阻塞队列中,等到
有空闲线程时从队列中取出执行
3.2、CachedThreadPool
核心线程数为0,最大为“无限”,默认县城如果空闲60s就被系统回收,可以一直扩容直到系统资源耗尽或者手动关闭
3.3、SingleThreadExecutor
不能扩容的线程池,是FixedThreadPool的特殊实现
3.4、ScheduledThreadPool
具有调度(定时)作用的线程池