线程池
池化技术
程序运行,本质:占用系统的资源!优化资源的使用=》池化技术
池化技术:事先准备好一些资源,有人用,就来拿,用完返回池
线程池的好处:
1、降低资源的消耗
2、提供响应的速度
3、方便管理
线程服用、可以控制最大并发数、管理线程
线程池:三大方法、7大参数、4种拒绝策略
三大方法
//使用线程池要用线程池创建线程
public class Demo1 {
public static void main(String[] args) {
// ExecutorService threadPool = Executors.newSingleThreadExecutor();//单个线程
// ExecutorService threadPool = Executors.newFixedThreadPool(5);//创建一个固定的线程池大小
ExecutorService threadPool = Executors.newCachedThreadPool();//可伸缩的
try {
for (int i = 0; i < 100; i++) {
threadPool.execute(()->{
System.out.println(Thread.currentThread().getName() + "ok");
});
}
//线程池用完需要结束线程池
}catch (Exception e){
e.printStackTrace();
}finally {
threadPool.shutdown();
}
}
}
最好不要通过Executors创建线程池,而是通过ThreadPoolExecutor的方式创建,避免内存泄漏
最大 线程为21亿线程
@Native public static final int MAX_VALUE = 0x7fffffff;
7大参数
public ThreadPoolExecutor(int corePoolSize, //核心线程池大小
int maximumPoolSize,//最大核心线程池大小
long keepAliveTime,//超时时间(没有人调用释放)
TimeUnit unit,//超时单位
BlockingQueue<Runnable> workQueue,//阻塞队列
ThreadFactory threadFactory) {//线程工厂,创建线程用的,一般不用动
this(corePoolSize, maximumPoolSize, keepAliveTime, unit, workQueue,
threadFactory, defaultHandler);//defaultHandler拒绝策略
}
4种拒绝策略
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-WNZuNrGO-1617319742111)(C:\Users\zyq zt\AppData\Roaming\Typora\typora-user-images\image-20210401215516907.png)]
public class Demo2 {
public static void main(String[] args) {
ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(2,
5,
3,
TimeUnit.SECONDS, new LinkedBlockingQueue<>(4),
// new ThreadPoolExecutor.CallerRunsPolicy(),
// new ThreadPoolExecutor.DiscardOldestPolicy(),
new ThreadPoolExecutor.DiscardPolicy());
//默认AbortPolicy拒绝策略 超过队列抛出异常容量为::最大核心线程池大小+阻塞队列数
//CallerRunsPolicy 哪里来的回哪里去
//ThreadPoolExecutor.DiscardPolicy() 队列满了不抛出异常
//ThreadPoolExecutor.DiscardOldestPolicy() 队列满了抛弃最老的
try {
for (int i = 1; i <= 10; i++) {
threadPoolExecutor.execute(()->{
System.out.println(Thread.currentThread().getName()+" ok");
});
}
}catch (Exception e){
e.printStackTrace();
}finally {
threadPoolExecutor.shutdown();
}
}
}
最大线程如何定义
(调优方式)
CPU密集型:几核就是可以定义多少个线程
IO密集型:判断你程序十分耗IO的线程,如果是15个,设置30个
四大函数式接口
lambda表达式
链式编程
函数式接口
Stream流计算
函数式接口
只有一个函数的接口,简化编程模型,在新版本的框架底层大量运用
List list = new ArrayList();
list.forEach();//函数式接口
public static void main(String[] args) {
// Function<T,R> //传入参数T,返回参数R
Function<String,Integer> function = (a) -> {return 2;};
System.out.println(function.apply("1"));
//断定型接口
Predicate<String> predicate = (str)->{ return str.isEmpty();};
System.out.println(predicate.test("aaa"));
//
}
public static void main(String[] args) {
//Consumer只有输入没有返回
Consumer<String> consumer = (str) -> System.out.println(str);
consumer.accept("aaa");
//Supplier值返回不输入
Supplier<String> supplier = () -> {return "aaa1";};
System.out.println(supplier.get());
}
流式计算
public class Test {
//链式编程
public static void main(String[] args) {
User u1 = new User(1,"zzz",21);
User u2 = new User(2,"www",22);
User u3 = new User(3,"yyy",23);
User u4 = new User(4,"ddd",24);
User u5 = new User(5,"sss",25);
List<User> list = Arrays.asList(u1, u2, u3, u4, u5);
Arrays.asList(u1,u2,u3,u4,u5).stream()
.filter(p -> p.getId()%2==0).forEach(System.out::println);
list.stream().map( u -> u.getName().toUpperCase(Locale.ROOT)).forEach(System.out::println);
}
}
ForkJoin
并行执行任务,提高效率
分而治之
特点:工作窃取====》原理双端队列
异步回调、
//异步调用ajax
//异步执行
//成功回调
public class Demo01 {
public static void main(String[] args) throws ExecutionException, InterruptedException {
//
CompletableFuture<Void> completableFuture = CompletableFuture.runAsync(()->{
try {
TimeUnit.SECONDS.sleep(1);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName() + "runAsync=>void");
});
System.out.println("==============");
completableFuture.get(); //获取阻塞执行结果
//有返回值的异步回调
CompletableFuture<Integer> completableFuture1 = CompletableFuture.supplyAsync(()->{
return 11;
});
System.out.println(completableFuture1.whenComplete((t, u) -> {
System.out.println(t);//正常返回结果
System.out.println(u);//错误信息
}).exceptionally((t) -> {
System.out.println(t.getMessage());
return 1;
}).get());
}
}
JMM
Volatiler:是java虚拟机提供轻量级的同步机制
保证可见性:怎么保证可见性—需要了解JMM
不保证原子性
禁止指令重排
关于JMM的一些同步的约定:
- 线程解锁前,必须把共享变量立刻刷新回主存
- 线程加锁前,必须读取主存中的最新值到工作内存中
- 加锁和解锁是同一把锁
线程分为 工作内存、主内存
8种操作
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-axmb9B9N-1617319742113)(C:\Users\zyq zt\AppData\Roaming\Typora\typora-user-images\image-20210402071025816.png)]
(1)lock(锁定):作用于 主内存的变量,把一个变量标记为一条线程独占状态
(2)unlock(解锁):作用于 主内存的变量,把一个处于锁定状态的变量释放出来,释放后的变量才可以被其他线程锁定
(3)read(读取):作用于 主内存的变量,把一个变量值从主内存传输到线程的 工作内存中,以便随后的load动作使用
(4)load(载入):作用于 工作内存的变量,它把read操作从主内存中得到的变量值放入工作内存的变量副本中
(5)use(使用):作用于 工作内存的变量,把工作内存中的一个变量值传递给执行引擎
(6)assign(赋值):作用于 工作内存的变量,它把一个从执行引擎接收到的值赋给工作内存的变量
(7)store(存储):作用于 工作内存的变量,把工作内存中的一个变量的值传送到 主内存中,以便随后的write的操作
(8)write(写入):作用于 工作内存的变量,它把store操作从工作内存中的一个变量的值传送到 主内存的变量中
保证可见性
public class JMMDemo {
//不加volatile会死循环
//volatile可以保证可见性
private volatile static int num = 0;
public static void main(String[] args) {
new Thread(()->{
while (num ==0){ //线程不知道内存种num值已经被修改了,会一直循环
}
}).start();
try {
TimeUnit.SECONDS.sleep(1);
}catch (InterruptedException e){
}
num = 1;
System.out.println(num);
}
}
不保证原子性
线程A执行任务的时候,不能被打扰,要么同时成功,要么同时失败
public class VDemo2 {
//volatile 不保证原子性 可通过lock和sychronized保证原子性
//不用锁如果保证原子性 num++不保证原子性
//可以使用原子类,处理原子问题(效率比锁高)
private volatile static AtomicInteger num = new AtomicInteger();
public static void add(){
// num ++;
num.getAndIncrement();
}
public static void main(String[] args) {
for (int i = 0; i < 20; i++) {
new Thread(()->{
for (int j = 0; j < 1000; j++) {
add();
}
}).start();
}
while (Thread.activeCount()>2) {
Thread.yield();
}
System.out.println(Thread.currentThread().getName() + "" + num);
}
}
{
new Thread(()->{
for (int j = 0; j < 1000; j++) {
add();
}
}).start();
}
while (Thread.activeCount()>2) {
Thread.yield();
}
System.out.println(Thread.currentThread().getName() + "" + num);
}
}
num.getAndIncrement();这些类的底层都是直接和操作系统挂钩,在内存中修改值!Unsafe类是一个很特殊的存在!