java并发
java并发常见面试题
sleep执行后线程进入阻塞状态
yield执行后线程进入就绪状态
join执行后线程进入阻塞状态
java中yiled()方法的作用是:让当前处于运行状态的线程退回到可运行状态,让出抢占资源的机会



死锁

sleep只有带参的两个方法,必须输入等待时间,而wait有三种重载方法。



java并发进阶
1.synchronized 关键字
synchronized 关键字解决的是多个线程之间访问资源的同步性,synchronized关键字可以保证被它修饰的方法或者代码块在任意时刻只能有一个线程执行。


volite特性:保持可见性,禁止jvm指令重排

构造方法不能使用synchronized修饰,因为构造方法本身就是线程安全的。在java的语言规范中提到,构造方法没必要加synchronized关键字,因为
在构建过程中是锁定的,其他线程不会调用没有实例化完成的对象。


比如偏向锁适合一个线程对一个锁的多次获取的情况; 轻量级锁适合锁执行体比较简单(即减少锁粒度或时间), 自旋一会儿就可以成功获取锁的情况.如果自旋次数达到threshold,就会升级为重量级锁,即1.6优化前的互斥锁。

逃逸分析:
逃逸分析的基本行为就是分析对象动态作用域:当一个对象在方法中被定义后,对象只在方法内部使用,则认为没有发生逃逸。
JVM判断新创建的对象是否逃逸的依据有:一、对象被赋值给堆中对象的字段和类的静态变量。二、对象被传进了不确定的代码中去运行。如果满足了以上情况的任意一种,那这个对象JVM就会判定为逃逸。对于第一种情况,因为对象被放进堆中,则其它线程就可以对其进行访问,所以对象的使用情况,编译器就无法再进行追踪。第二种情况相当于JVM在解析普通的字节码的时候,如果没有发生JIT即时编译,编译器是不能事先完整知道这段代码会对对象做什么操作。保守一点,这个时候也只能把对象是当作是逃逸来处理。
使用逃逸分析,编译器可以对代码做如下优化:
栈上分配:将堆分配转化为栈分配。如果一个对象在子程序中被分配,要使指向该对象的指针永远不会发生逃逸,对象可能是栈上分配的候选,而不是堆上分配
锁消除:如果一个对象被发现只有一个线程被访问到,那么对于这个对象的操作可以不考虑同步。


volatile关键字
CPU高速缓存相当于CPU与内存之间的缓存,内存可以看作和外存的缓存。
总结:CPU Cache 缓存的是内存数据用于解决 CPU 处理速度和内存不匹配的问题,内存缓存的是硬盘数据用于解决硬盘访问速度过慢的问题。
volatile关键字修饰的变量会告诉JVM这个变量必须从主存(共享内存读取)


acid:原子性、隔离性、一致性、持久性。

ThreadLocal

Thread类里面有两个ThreadLocalMap对象,属于线程自己的变量都存在这里面,ThreadLocal的set方法只是获取到当前Thread的ThreadLocalMap对象然后存进去。并不是存在ThreadLocal对象里。

如下图,每个线程只会访问自己线程ThreadLocalMap里的数据,ThreadLocal为key。

ThreadLocal内存泄漏问题:简单来说就是ThreadLocalMap中的Key ThreadLocal使用的是弱引用,value是强引用类型,如果 ThreadLocal 没有被外部强引用的情况下,在垃圾回收的时候,key 会被清理掉,而 value 不会被清理掉。这样一来,ThreadLocalMap 中就会出现 key 为 null 的 Entry。假如我们不做任何措施的话,value 永远无法被 GC 回收,这个时候就可能会产生内存泄露。



线程池



如何创建线程池:

当任务数量>核心线程数,多余的放在任务队列,任务队列满了后,那么可以同时运行线程数量就会变成设置的最大线程数。


线程池原理:

Atomic原子类



CAS算法:


AQS:




CompletableFuture并发:

重要知识点没有看 后面需要补充

整理自:https://javaguide.cn/
浙公网安备 33010602011771号