1、java线程池最顶级的接口Executor
只有一个execute方法,这个方法时用来执行Runnable类型的command实例的
2、Executor接口的子接口ExecutorService
可以看到里面提供的方法
submit() :提交一个"任务",既可以是Runnable也可以是Callable
shutdown() :优雅的关闭一个线程池,如果关闭时线程池中还有执行的任务,则不再接受新的任务,并把没有执行完毕的任务全部执行完毕后再关闭,并回收所有线程。
shutdownNow(): 粗暴地关闭线程池,不管是不是还有任务正在执行,并回收所有线程。
isShutdown() 是不是已经关闭了,只要调用了shutdown()就返回true
isTerminated() 是不是彻底关闭了
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.*;
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<Long> c1 = ()->{
long result = 0;
for(int i=1;i<=100;i++){
result+= i;
}
return result;
};
/**
* 测试FixedThreadPool和shutdown()以及isTerminated
* newFixedThreadPool的特点有固定的大小
* 大小不可扩展,默认的生命周期为无限即要么虚拟机关闭,要么调用shutdown()方法
* 否则线程池一直活着
* 使用场景:一般情况下使用线程池的首选
*/
@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()方法时阻塞的
*/
@Test
public void test2(){
ExecutorService p1 = Executors.newCachedThreadPool();
Callable<Long>[] arr = new Callable[5];
Arrays.fill(arr,c1);
List<Future> futures = new ArrayList<>();
for(Callable c : arr){
Future<Long> f = p1.submit(c);
futures.add(f);
}
long result = 0;
for(Future<Long> 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 一个线程池里只有一个线程
* 使用场景:保证任务顺序,比如多人聊天室里面的公告,发送一个公告可以由一个线程执行以确保公告的有序执行
*/
@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);
/**
* 按照固定的频率,没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);
}
}
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<arr.length;i++){
arr[i]=i;
}
ForkJoinPool pool = new ForkJoinPool();
JoinTask task = new JoinTask(arr,0,arr.length,50);
Future<Long> future = pool.submit(task);
System.out.println(future.get());
}
}
class JoinTask extends RecursiveTask<Long>{
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<end;i++){
result+= arr[i];
}
return result;
}else{
int mid = start + (end - start)/2;
JoinTask j1 = new JoinTask(arr,start,mid,target);
JoinTask j2 = new JoinTask(arr,mid,end,target);
//fork()方法时继续查分即会继续调用compute方法
j1.fork();
j2.fork();
return j1.join()+j2.join();
}
}
}