1、CAS算法 无锁优化 自旋锁
CompareAndSwap 比较和交换
AtomicInteger i = new AtmoicInteger();
i.incrementAndGet();//自增并返回结果
//incrementAndGet() 方法跟踪进去会发现底层是调用的native方法 ( Unsafe.class类中的
//public final native boolean compareAndSwapInt(...) )
//最终执行的就是linux底层的一条汇编指令 lock cmpxchg 指令
//synchronized 和 volatile 最终底层都是使用 lock cmpxchg 指令
ABA问题:线程1读取了数据0做++,回来校验原值时,这个过程中,其他线程对数据0做了修改,只是最终结果又变成了0,即原值为A,过程中被改为了B,最终又被改为了A,就是ABA问题。
解决办法:数据0加上版本号,每个线程读取数据0时连同版本号一起读取, 每次处理完回来比较的时候连同版本号一起比较即可。 AtomicStampedReference 可带版本
2、sychronized 与 对象在内存中的布局息息相关
2.1、锁的4种状态及升级过程
new(无锁状态)-----> 偏向锁(第一次上锁)-----> 轻量锁(有人竞争时) -----> 重量锁(竞争激烈时)
下图 为锁的布局信息,markword共64位,8个字节,都在markword里
2.2、sychronized的执行过程;
a.编码阶段:java代码:sychronized关键字
b.编译阶段:class文件:moniterenter------->moniterexit
c.运行阶段:执行过程种锁自动升级
d.底层实现:lock comxchg
3、volatile
3.1、线程可见性(,无法保证原子性,无法替代synchronized)
MESI 缓存一致性协议
不通型号的cpu的每个缓存行大小不通,如 X86 是 32BYTES ,而 ALPHA 是 64个字节,
这里面有缓存行对齐的概念,即,让一个变量始终独占一个缓存行,处理这个变量的线程在修改主内存里的这个变量时,不需要通知其他线程来同步这个变量;当使用volatile关键字修饰时,多线程下对性能有很大的提高,典型案例 Disruptor 开源的并发框架
3.2、禁止cpu指令重排序
DCL单例 Double Check Lock
cpu的乱序执行(重排序),cpu先后接收互不影响的指令1和指令2,指令1执行很慢,这时在等待指令1返回结果的时候,cpu把指令2执行完了,这种情况就是cpu的乱序执行,单线程下没问题,多线程下会有问题。
3.2.1、jvm内存屏障
jvm的内存屏障两边的指令不可以重排序,保证指令的有序性;
Load读,Store写
volatile关键字解决cpu指令重排序的方式:
代码层面使用volatile关键字修饰,编译后的字节码文件也只是增加了volatile关键字,加载到jvm时,jvm根据其自身的规范,在看到volatile关键字时,开始添加内存屏障,使用两个内存屏障把volatile修饰的操作隔离起来,上屏障之前的指令都做完,才能执行volatile操作,volatile操作执行完,才能执行下屏障后面的指令 ,这样就是实现了禁止指令重排序(乱序执行)
4、ThreadLocal
4.1、java对象与引用类型 强 软 弱 虚
强类型:普通引用类型
软引用: 用于缓存管理,空间不够用的时候就会被自动回收
java.lang.ref.SoftReference<byte[]> sr = new SoftReference<>(new byte[1024*1024*10]);
弱引用:管理一次性的对象,一旦遇到垃圾回收,就会被回收掉
ThreadLocal: 线程本地对象,每个线程独自拥有,其内部的东西(对象、数据、连接等)其他线程不可见,线程存在,ThreadLocal对象就一直存在
Spring中@Transactional注解就是使用ThreadLocal实现的事务管理,当一个方法m()使用@Transactional注解修饰,其内部又调用了m1()和m2()两个方法,这两个方法都要连接数据库,只有m1和m2使用的是同一个数据库连接时,才能保证事务,此处数据库连接就是放在ThreadLocal中的。
public class ThreadLocalDemo {
static ThreadLocal<Person> tl = new ThreadLocal<>();
public static void main(String[] args) {
new Thread(() -> {
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(tl.get());
}).start();
new Thread(() -> {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
tl.set(new Person());
}).start();
}
static class Person{
String name = "zhangsan";
}
}
WeakReference
/**
* 弱引用类型------一次性的对象场景
* @author zxj
* @date 2020/5/11 8:39
*/
public class _WeakReference {
public static void main(String[] args) {
WeakReference<M> m = new WeakReference<>(new M());
System.out.println(m.get());
System.gc();
System.out.println(m.get());
ThreadLocal<M> t1 = new ThreadLocal<>();
t1.set(new M());// 追踪源码
t1.remove(); //当set进去的数据无用时,必须手动清理set进去的数据,否则底层的map由于key时弱引用,遇到gc就被回收了,但是map里的value还存在,不手动清理,会造成内存泄漏
}
}
t1.set()源码
map.set()源码
new Entry()源码
虚引用:管理堆外内存的
/**
* 虚引用类型 ---- 管理堆外内存 off heap
* @author zxj
* @date 2020/5/11 8:43
*/
public class _PhantomReference {
private static final List<Object> LIST = new LinkedList<>();
private static final ReferenceQueue<M> QUEUE = new ReferenceQueue<>();
public static void main(String[] args) {
PhantomReference<M> phantomReference = new PhantomReference<>(new M(), QUEUE);
new Thread(() -> {
while(true){
LIST.add(new byte[1024*1024]);
try{
Thread.sleep(1000);
}catch (InterruptedException e){
e.printStackTrace();
Thread.currentThread().interrupt();
}
System.out.println(phantomReference.get());
}
}).start();
new Thread(() -> {
while (true){
Reference<? extends M> poll = QUEUE.poll();
if(poll != null){
System.out.println("---虚引用对象被jvm回收了----" + poll);
}
}
}).start();
try {
Thread.sleep(500);
}catch (InterruptedException e){
e.printStackTrace();
}
}
}
零拷贝技术