synchronized使用:
同步代码块
synchronized(this|任意一个Object子类对象|当前类.class) {
}
同步方法
修饰普通对象方法 锁当前对象this
修饰类的静态方法 锁当前类.class
保护的是什么?几个锁?
使用一把锁锁住了两个毫无关系的对象
如何保护毫无关系的资源?
使用多把锁锁住不同的资源
class Account { // 余额 int sal; // 密码 String password; // 余额资源的锁 private Object salLock = new Object(); // 密码资源的锁 private Object passLock = new Object(); public int getMoney() { synchorinzed(salLock) {} } public void setMoney() { synchorinzed(salLock) {} } public String getPassword() { synchorinzed(passLock) {} } public void setPassword() { synchorinzed(passLock) {} } }
转账
A -> B 100
A -= 100;
B += 100;
如何保护有关联关系的对象:
使用同一把锁
public void zhuangzhang(Account target) { synchroinzed(Account.class) { this.sal -= 100; target.sal += 100; } }
由于转账涉及两个账户间的sal操作,因此需要将两个账户同时锁定。
由于方法的synchrond只能锁一个对象,因此锁不住转账操作
这个时候要看synchronized底层实现
synchronized底层实现:
在使用synchronized时必须保证锁定对象必须为Object以及其子类对象。
synchronized使用的是JVM层级别的MonitorEnter与MonitorExit实现。
这两个指令都必须获取对象的同步监视器Monitor
对象锁Monitor机制
monitorenter:
检查obj对象的Monitor计数器值是否为0,为0表示此监视器还未被任意一个线程获取,此时线程可以进入同步代码块并且将Monitor值+1,将Monitor的持有线程标记为当前线程
当Monitor计数器值不为0且持有线程不是当前线程,表示Monitor已经被别的线程占用,当前线程只能阻塞等待。
当Monitor计数器值不为0但是持有线程恰好是当前线程,
monitorexit:
Monitor计数器值-1
可重入锁:
当执行MonitorEnter时。对象的Monitor计数器值不为0,但是持有线程恰好是当前线程,
此时将Monitor计数器值再次+1,当前线程继续进入同步方法或代码块,就好比上面第一个代码,我调用getMoney()方法的时候,getMoney()方法里面也可以调用getPassword()方法
CAS操作(无锁实现的同步-乐观锁)-自旋
class Test { int i = 0; // 线程1 synchronized(this) { i = 10; } }
CompareAndSwap(O,V,N)
O:当前线程存储的变量值 0
V:内存中该变量的具体值 10
N:希望修改后的变量值 10
当O==V时,此时表示还没有线程修改共享变量的值,此时可以成功的将内存中的值修改为N
当O!=V时,表示此时内存中的共享变量值已被其他线程修改,此时返回内存中的最新值V,再次尝试修改变量
线程挂起阻塞:车熄火
自旋:脚踩刹车,车不熄火
1.ABA问题:
解决ABA问题添加版本号
2.自旋在CPU上跑无用指令,会浪费CPU资源
自适应自旋
JVM尝试自旋一段时间,若在此时间内,线程成功获取到锁,再下次获取锁时,适当延长自旋时间。
若在此时间内,线程没有获取到锁,再下次获取锁时,适当缩短自旋时间。
3.公平性问题
处于阻塞态线程可能会一直无法获取到锁
Lock锁可以实现公平性,synchronized无法实现公平锁
偏向锁:JDK1.6之后默认synchronized
最乐观的锁:进入同步快或同步方法的始终是一个线程
当出现另一个线程也尝试获取锁(在不同时刻)时,偏向锁会升级为轻量级锁
轻量级锁
不同时刻有不同的线程尝试获取锁,"量黄灯策略"
同一时刻有不同线程尝试获取锁,会将偏向锁升级为重量锁
重量级锁
JDK1.6之前synchronized都是重量级锁,将线程阻塞挂起(JDK1.6自适应自旋)
锁只有升级过程没有降级过程
锁粗化
当出现多次连续的加锁与解锁过程,会将多次加减锁过程粗化为一次的加锁与解锁过程
死锁:
死锁产生条件:以下四种条件同时满足才会导致死锁
1.互斥
共享资源只能同时被一个线程占用
2.占用且等待
3.不可抢占
线程T1拿到了资源X的锁,其他线程不能抢占X锁
4.循环等待
线程T1拿到了资源X的锁,去申请Y的锁
线程T2拿到了资源Y的锁,去申请X的锁
原文:https://www.cnblogs.com/du001011/p/11001177.html