线程池
目录
- 1、ThreadPoolExecutor的七个参数:
- 2、线程池的底层工作原理:
- 3、面试题(为什么不用jdk提供的线程Execuetor)
- 4、线程池的拒绝策略
- 5、Stream四大函数接口
- 6、Stream流式计算
- 7、ForkJoin
- 8、CompletableFutrue
- 异步编排(组合式编程)
- 9、Callable
package com.tfxing;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class Test01_ThreadPool {
public static void main(String[] args) {
//1、创建固定数量线程的线程池 适用于执行长期任务,性能好
// ExecutorService threadPool = Executors.newFixedThreadPool(3);
//2、创建单个数量线程的线程池 任何时候都只有一个线程再执行,能保证任务的有序性
// ExecutorService threadPool = Executors.newSingleThreadExecutor();
//3、可扩展线程的线程池 适用于短时异步任务
ExecutorService threadPool = Executors.newCachedThreadPool();
for (int i = 0; i < 10; i++) {
int count = i;
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+"\t号银行柜台为"+count+"位客户服务");
});
}
threadPool.shutdown();
}
}
使用ThreadPoolExecutor创建线程池:
@Configuration
public class ThreadPoolConfig {
@Bean
public ThreadPoolExecutor threadPoolExecutor(){
return new ThreadPoolExecutor(50,100,3, TimeUnit.SECONDS,
new ArrayBlockingQueue<>(10000));
}
}
ThreadPoolExecutor源码:
public ThreadPoolExecutor(int corePoolSize,
int maximumPoolSize,
long keepAliveTime,
TimeUnit unit,
BlockingQueue<Runnable> workQueue,
ThreadFactory threadFactory,
RejectedExecutionHandler handler) {
if (corePoolSize < 0 ||
maximumPoolSize <= 0 ||
maximumPoolSize < corePoolSize ||
keepAliveTime < 0)
throw new IllegalArgumentException();
if (workQueue == null || threadFactory == null || handler == null)
throw new NullPointerException();
this.acc = System.getSecurityManager() == null ?
null :
AccessController.getContext();
this.corePoolSize = corePoolSize;
this.maximumPoolSize = maximumPoolSize;
this.workQueue = workQueue;
this.keepAliveTime = unit.toNanos(keepAliveTime);
this.threadFactory = threadFactory;
this.handler = handler;
}
1、ThreadPoolExecutor的七个参数:
ThreadPoolExecutor的七个参数:
corePoolSize:线程池中的常驻核心线程数
maximumPoolSize:线程池中能够容纳同时执行的最大线程数,此值必须大于等于1
keepAliveTime:多余的空闲线程的存活时间,当前池中线程数量超过corePoolSize时,
闲时间达到keepAliveTime时,
多余线程会被销毁直到只剩下corePoolSize个线程为止
unit:keepAliveTime的单位(例如:TimeUnit.SECONDS)秒
workQueue:任务队列,被提交单未被执行的任务
threadFactory:表示生成线程池中工作线程的线程工厂,用于创建线程,一般默认的即可
handler: 拒绝策略,表示队列满了,并且工作线程大于等于线程池的最大线程数(maximumPoolSize)时,
如何来拒绝请求执行的runnable的策略
2、线程池的底层工作原理:
1、在创建了线程池后,开始等待请求
2、当调用了execute()方法添加一个请求任务时,线程池会做出如下判断:
2.1 、如果正在运行的线程数量小于corePoolSize,那么马上创建线程运行这个任务
2.2、如果正在运行的线程数量大于或等于corePoolSize,那么将这个任务放入队列
2.3、如果这个时候队列满了且正在运行的线程数量还小于maximumPoolSize,那么还是要创建非核心数线程来立刻运行这个任务
2.4、如果队列满了,且正在运行的线程数量大于等于maximumPoolSize,那么线程池会启动饱和拒绝策略来执行。
3、当一个线程完成任务时,它会从队列中取下一个任务来执行
4、当一个线程无事可做超过一定时间(keepAliveTime)时,线程会进行判断:
4.1、如果当前运行的线程数大于corePoolSize,那么这个线程会被停掉
4.2、所有线程池的所有任务完成后,它最终会收缩到corePoolSize的大小
线程进来后,如果corePoolSize已经满了,那么到workQueue中等待,如果再有线程进来,此时corePoolSize
和workQueue都满了,那么将线程数扩大到maximumPoolSize个(corePoolSize和扩容数的总和为maximumPoolSize)
,如果这时还有线程进入,此时maximumPoolSize和workQueue都满了,这时使用拒绝策略。当线程执行完毕后
如果扩容线程在keepAliveTime时间内没有线程进入,会将刚才的扩容线程关闭。
3、面试题(为什么不用jdk提供的线程Execuetor)
Executors返回的线程池对象的弊端:
1、FixedThreadPool和SingleThreadPool:允许请求队列的长度为Integer.MAX_VALUE,可能会堆积大量的请求,从而导致oom(out of memory)内存溢出
2、CacheThreadPool和ScheduledThreadPool:允许创建的线程数量为Integer.MAX_VALUE,可能会创建大量的线程,从而导致oom(out of memory)内存溢出
4、线程池的拒绝策略
4.1、AbortPolicy(默认):直接抛出RejectedExecutionException异常组织系统正常运行
4.2、CallerRunsPolicy:“调用者运行”,一种调节机制,该策略既不会抛弃任务,也不会抛出异常,而是将某些任务回退到调用者,从而降低新任务的流量
4.3、DiscardOldestPolicy:抛弃队列中等待最久的任务,然后把当前任务加入队列中尝试再次提交到当前任务
4.4、DiscardPolicy:该策略默默的抛弃无法处理的任务,不予任何处理也不抛出异常。如果允许任务丢失,这是最好的一种策略
4.2、测试代码
maximumPoolSize = Runtime.getRuntime().availableProcessors() + 1 //系统核数加1或2
import java.util.concurrent.*;
public class ExectorTest {
public static void main(String[] args) {
ExecutorService threadPool = new ThreadPoolExecutor(2,
5,//Runtime.getRuntime().availableProcessors() + 1 //系统核数加1或2
3,
TimeUnit.SECONDS,
new ArrayBlockingQueue<>(5),//等待队列
Executors.defaultThreadFactory(),//线程工厂
new ThreadPoolExecutor.DiscardPolicy());//DiscardOldestPolicy());//CallerRunsPolicy());返回上一级//AbortPolicy());//拒绝策略,这里时默认的拒绝策略,直接报异常
for (int i = 0; i < 20; i++) {
int finalI = i;
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName()+":"+ finalI);
});
}
}
}
5、Stream四大函数接口
Function:函数型接口
Function<String,Integer> function = s -> s.length();
System.out.println(function.apply("string")); // 6
Predicate:断定型接口
Predicate<String> predicate = s -> s.length()>0;
System.out.println(predicate.test("hello")); // true
Consumer:消费型接口
Consumer<String> consumer = s -> System.out.println(s);
consumer.accept("hello world");// hello world
Supplier:供给型接口
Supplier<String> supplier = ()-> "hello world";
System.out.println(supplier.get());// hello world
6、Stream流式计算
filter:需要传Predicate断定型接口
List<Integer> list = Arrays.asList(1,2,4,3,8,5);
list.stream().filter(l -> l % 2 == 0).filter(l -> l > 4).forEach(x-> System.out.println(x));
map:需要传Function函数型接口
List<Integer> list = Arrays.asList(1,2,4,3,8,5);
list.stream().filter(l -> l % 2 == 0).filter(l -> l > 4)
.map(n -> n + 1).forEach(x-> System.out.println(x));
Collect(Collectors.toList):转换成一个List并返回
List<Integer> list2 = Arrays.asList(1,24,5,6,2,5);
list2.stream().map(num -> num * 2).collect(Collectors.toList())
.forEach(num -> System.out.println(num));
Sorted:需要传入Compare接口
7、ForkJoin
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.concurrent.ForkJoinTask;
import java.util.concurrent.RecursiveTask;
class MyTask extends RecursiveTask<Integer>{
private static final Integer ADJUST_VALUE = 10;
private int begin;
private int end;
private int result;
public MyTask(int begin, int end) {
this.begin = begin;
this.end = end;
}
@Override
protected Integer compute() {
if((end - begin)<=ADJUST_VALUE){
for(int i =begin;i <= end;i++){
result = result + i;
}
}else{
int middle = (begin + end)/2;
MyTask task01 = new MyTask(begin,middle);
MyTask task02 = new MyTask(middle+1,end);
task01.fork();
task02.fork();
result = task01.join() + task02.join();
}
return result;
}
}
/**
* 分支合并例子
* ForkJoinPool
* ForkJoinTask
* RecursiveTask
*/
public class ForkJoinDemo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyTask myTask = new MyTask(0,100);
ForkJoinPool forkJoinPool = new ForkJoinPool();
ForkJoinTask<Integer> forkJoinTask = forkJoinPool.submit(myTask);
System.out.println(forkJoinTask.get());
forkJoinPool.shutdown();
}
}
8、CompletableFutrue
import java.util.concurrent.CompletableFuture;
public class CompletableFutureDemo {
public static void main(String[] args) {
//runAsync:没有返回值
CompletableFuture<Void> voidCompletableFuture = CompletableFuture.runAsync(() -> {
System.out.println("没有返回值");
});
//supplyAsync:异步调用,有返回值
CompletableFuture<Integer> integerCompletableFuture = CompletableFuture.supplyAsync(() -> {
System.out.println("有返回值");
return 1024;
});
integerCompletableFuture.whenComplete((t,u)->{//正常情况
System.out.println("tttt:"+t);
System.out.println("uuuu:"+u);
}).exceptionally(f->{//异常情况
System.out.println("excption:"+f.getMessage());
return 404;
});
}
}
异步编排(组合式编程)
CompletableFuture<T>
线程的独立创建:
有返回值线程:supply
无返回值线程:run
线程的依赖创建:
有返回值:apply
无返回值:accept
同步或异步
异步执行:async
同步执行:sync
线程执行的组合:
AllOf(a,b,c):用来阻塞主线程的执行,必须所有线程都执行完成,才能返回结果
anyOf(a,b,c):只有某一个线程执行完毕就返回,不影响其他线程
exceptionally():线程执行出现异常时调用
whenComplate():线程执行完毕后调用
9、Callable
9.1、Callable接口和Runnable接口之间的区别(三种不同)
callable有泛型
1、callable的实现方法是call方法,runnable的实现方法是run方法,
2、call方法可以抛出异常,run方法不能抛出异常
3、call方法有返回值,run方法没有返回值
@FunctionalInterface
public interface Callable<V> {
/**
* Computes a result, or throws an exception if unable to do so.
*
* @return computed result
* @throws Exception if unable to compute a result
*/
V call() throws Exception;
}
@FunctionalInterface
public interface Runnable {
/**
* When an object implementing interface <code>Runnable</code> is used
* to create a thread, starting the thread causes the object's
* <code>run</code> method to be called in that separately executing
* thread.
* <p>
* The general contract of the method <code>run</code> is that it may
* take any action whatsoever.
*
* @see java.lang.Thread#run()
*/
public abstract void run();
}