线程池
线程池:七大参数,四中拒绝策略
池化技术: 程序本质 :占用系统资源,要去优化资源的使用==>池化技术
资源的创建和销毁十分浪费系统资源
池化技术就是事先准备一些资源,如果有人要用就来我这里拿,用完还给我,以此提高效率
线程池的好处:
1.降低资源的消耗
2.提高响应速度
3.方便管理
线程池三大方法:
ExecutorService Service = Executors.newSingleThreadExecutor();//单个线程
ExecutorService Service1 = Executors.newFixedThreadPool(5);//创建一个该规定的线程池大小
ExecutorService Service2 = Executors.newCachedThreadPool();//可伸缩的线程池大小
public class ThreadPoolTest {
public static void main(String[] args) {
ExecutorService executorService = Executors.newSingleThreadExecutor();//单个线程
ExecutorService executorService1 = Executors.newFixedThreadPool(5);//创建一个该规定的线程池大小
ExecutorService executorService2 = Executors.newCachedThreadPool();//可伸缩的线程池大小
try {
//通过线程池去创建线程
for (int i = 0; i < 10; i++) {
executorService1.execute(()->{
System.out.println(Thread.currentThread().getName()+"创建ok");
});
}
} catch (Exception e) {
e.printStackTrace();
} finally {
//不使用的话要关闭线程池
executorService1.shutdown();
}
}
}
七大参数:
源码剖析:
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;
}
小狂神的银行排队案例:
阿里巴巴开发手册里面写到我们最好使用new ThreadPoolExecutor去创建线程池,传统的Executors工具类创建不安全,所以我们都要使用new ThreadPoolExecutor去创建线程池
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2,
5,
3L,
TimeUnit.SECONDS,
new LinkedBlockingDeque<>(3),
Executors.defaultThreadFactory(),
new ThreadPoolExecutor.AbortPolicy());
四种拒绝策略:
//四种拒绝策略
// new ThreadPoolExecutor.AbortPolicy(); //不处理任务,抛出异常java.util.concurrent.RejectedExecutionException:
// new ThreadPoolExecutor.CallerRunsPolicy(); //哪里来的回到哪里去
// new ThreadPoolExecutor.DiscardOldestPolicy();//尝试跟第一个线程竞争,竞争不上就丢弃掉
// new ThreadPoolExecutor.DiscardPolicy();//丢弃任务,不抛出异常
//最大承载 : 最大核心线程池的数量加上阻塞队列的数量
线程最大数量的设计:
调优:
-
CPU密集型:更加CPU的核心数设定max–Runtime.getRuntime().availableProcessors()
-
IO密集型:设定的线程数得满足耗时任务的执行,起码要大于它。
四大函数式接口(必须掌握)
新时代的程序员要会的:lambda表达式,链式编程,函数式接口, Stream流式计算
函数式接口:只有一个方法的接口,如:Runable, Callable.......
@FunctionalInterface
public interface Runnable {
public abstract void run();
}
Function函数式接口源码分析:
/**
* Function函数式接口
*/
public class demo01 {
public static void main(String[] args) {
// Function function = new Function<String,String>() {
// @Override
// public String apply(String str) {
// return str;
// }
// };
//所有的函数式接口都可以用lambda表达式简化
Function function=(str)->{return str;};
System.out.println(function.apply("abc"));
}
}
predicate函数式接口:断定型接口,只有一个输入参数,返回值只能是布尔值!
可以用来判断输入的字符串是否为空,也可以用lambda表达式简化,只要是函数式接口,都可以用lambda表达式简化
消费者型Consumer接口
public class demo03 {
public static void main(String[] args) {
// Consumer<String> consumer = new Consumer<String>() {
//
// @Override
// public void accept(String str) {
// System.out.println(str);
// }
// };
Consumer<String> consumer=(str)->{
System.out.println(str);
};
consumer.accept("哈哈哈");
}
}
Supplier供给型接口
/**
* 供给型接口,只有返回值,没有输入值,
*/
public class demo04 {
public static void main(String[] args) {
// Supplier<String> supplier = new Supplier<String>() {
// @Override
// public String get() {
//
// return "哈哈哈哈哈";
// }
// };
Supplier<String> supplier=()->{
return "hahahah";
};
System.out.println(supplier.get());
}
}
Stream流式计算
大数据:存储+计算
存储: 集合,MySQL;
package Steam;
import java.util.Arrays;
import java.util.List;
/**
* 要求: 一分钟内完成,只能用一行代码
* 现在有五个用户!请进行筛选
* 1.id必须是偶数
* 2.年龄必须大于23岁
* 3.用户名转换为大写
* 4.用户名字母倒着排序
* 5.只输入一个用户
*/
public class Test {
public static void main(String[] args) {
List<User> list = Arrays.asList(
new User(1, "a", 21)
, new User(2, "b", 20)
, new User(3, "c", 23)
, new User(4, "d", 28)
, new User(6, "e", 24)
);
//把集合装换为流对象
list.stream()
.filter(u->{return u.getId()%2==0;})
.filter(u->{return u.getAge()>23;})
.map(u -> {return u.getName().toUpperCase();})
.sorted((uu1,uu2)->{return uu2.compareTo(uu1);})
.limit(1)
.forEach(System.out::println);
}
}
ForkJoin
什么是ForkJoin?
主要是并行执行任务,提高效率! 大数据量
把大任务拆分为小任务
ForkJoin的特点: 工作窃取:比如现在有两个队列,分别有几个小任务在里边,分别有两条线程去跑,如果b线程还没跑完,a线程已经跑完了,a线程就会执行b线程中还没完成的任务
如何使用ForkJoin?
1.创建ForkJoinPool 通过它来执行 他的执行方法
2.计算任务:forkjoinPool.execute(ForkJoinTask task) 执行
我们这里写一个计算的任务类继承RecursiveTask类(有返回值的)demo1
/**
* 求和计算的任务
* 有三种写法
* 1.传统for循环
* 2.forkJoin
* 3.Stream并行流
* //如何使用ForkJoin
* 1.forkjoinPool 通过它来执行
* 2.计算任务:forkjoinPool.execute(ForkJoinTask task) 执行
* 3.计算类要继承RecursiveTask<Long>类
*/
public class demo1 extends RecursiveTask<Long> {
private long start;
private long end;
//临界值
private static long temp=10000L;
public demo1(Long start, Long end) {
this.start = start;
this.end = end;
}
//计算的方法
//这里定义了一个临界值,如果大于这个临界值就会使用我们的ForkJoin方法,如果不大于临界值就使用我们定义的传统方法去计算
@Override
protected Long compute() {
if ((end-start)<=temp){
Long sum=0L;
for (Long i = start; i <=end ; i++) {
sum +=i;
}
return sum;
}else{//forkJoin 递归
//大事化小,小事化了
long middle=(start+end) / 2;//中间值
demo1 task1 = new demo1(start, middle);
task1.fork();//拆分任务,把任务压入线程队列
demo1 task2 = new demo1(middle+1, end);
task2.fork();//拆分任务,把任务压入线程队列
return task1.join() + task2.join();
}
}
}
接下来写一个测试类,有三种方法,第一种是传统方法,第二种是使用了ForkJoin的,第三种是使用了Stream并发流的计算的,也是效率最高的那一种,所有的计算都应该让stream流来做
异步调用Future
Future的设计初衷:对将来的某个事件的结果进行建模
CompletableFuture是Future接口的一个实现类,我们用它来发起一个请求,(没有返回值的)
/**
* 异步调用
* 执行成功有成功的回调
* 失败回调
*/
public class demo {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//发起一个请求
CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(()->{
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"runAsync=>Void");
});
System.out.println("11111111");
completableFuture.get();//获取阻塞执行结果
}
}
runAsync方法发起一个异步请求, get()方法为阻塞获取执行的结果
执行顺序:这里模拟了延时,
还有另外一种方法(有返回值的)
//有返回值的
//这里的参数需要的是一个供给型参数 没有输入值,只有一个返回值
CompletableFuture<Integer> completableFuture = CompletableFuture.supplyAsync(()->{
System.out.println(Thread.currentThread().getName()+"supplyAsync=>Integer");
int i =10/0;//这里制造一个错误
return 1024;
});
//成功回调
//这里需要的参数是一个BiConsumer消费型参数,是Consumer的增强型,他需要的是两个参数
System.out.println(completableFuture.whenComplete((t, u) -> {
System.out.println("t" + t); //这是正常的返回结果
System.out.println("u" + u); //
}).exceptionally((e) -> { //失败回调
System.out.println(e.getMessage());
return 233; //可以获取错误的返回结果
}).get());
}
成功回调方法whenComplete(),失败回调方法:exceptionally()