死锁
【死锁】在JAVA编程中,有3种典型的死锁类型:
- 静态的锁顺序死锁
- 动态的锁顺序死锁
- 协作对象之间发生的死锁
//可能发生静态锁顺序死锁的代码
static class StaticLockOrderDeadLock{
private final Object lockA=new Object();
private final Object lockB=new Object();
public void a(){
synchronized (lockA) {
//...
//线程1 运行到这里,持有lockA,等待lockB
synchronized (lockB) {
System.out.println("function a");
}
}
}public void b(){
synchronized (lockB) {
//...
//线程2 运行到这里,持有lockB,等待lockA
synchronized (lockA) {
System.out.println("function b");
}
}
}
}
- 解决静态的锁顺序死锁的方法就是:所有需要多个锁的线程,都要以相同的顺序来获得锁。
//正确的代码
static class StaticLockOrderDeadLock2{
private final Object lockA=new Object();
private final Object lockB=new Object();
public void a(){
synchronized (lockA) {
synchronized (lockB) {
System.out.println("function a");
}
}
}public void b(){
synchronized (lockA) {
synchronized (lockB) {
System.out.println("function b");
}
}
}
}
- 动态的锁顺序死锁解决方案如下:使用System.identifyHashCode()返回hashcode的大小来保证锁的顺序。确保所有的线程都以相同的顺序获得锁
//正确的代码
static class DynamicLockOrderDeadLock2{private final Object myLock=new Object();
public void method(Object lockA, Object lockB){
intfromLockA = System.identityHashCode(lockA);
intfromLockB = System.identityHashCode(lockB);
if(fromLockA < fromLockB){
getResource(lockA, lockB);
}else if(fromLockA > fromLockB){
getResource(lockB, lockA);
}else {
synchronized (myLock) {
getResource(lockA, lockB);
}
}
}private void getResource(Object lockA, Object lockB) {
synchronized (lockA) {
synchronized (lockB){
System.out.println("DynamicLockOrderDeadLock -- " + index);
index++;
}
}
}
}
协作对象之间发生的死锁: 有时,死锁并不会那么明显,比如两个相互协作的类之间的死锁,比如下面的代码:一个线程调用了ModelA对象的setA方法,另一个线程调用了ModelB对象的method方法。此时可能会发生,第一个线程持有ModelA对象锁并等待ModelB对象锁,另一个线程持有ModelB对象锁并等待ModelA对象锁。
//可能发生死锁
static class ModelA{private int a;
private ModelB modelB;
public ModelA(ModelB modelB) {
this.modelB = modelB;
}public synchronized void setA(int a) {
this.a = a;
modelB.addModelA(this);
}public synchronized int getA() {
return a;
}@Override
public String toString() {
return "ModelA{" +
"a=" + a +
'}';
}
}static class ModelB{private final List modelAS = new ArrayList<>();
public synchronized void addModelA(ModelA modelA){
modelAS.add(modelA);
}public synchronized void method(){
for (ModelA modelA:modelAS) {
System.out.println(" a: " + modelA.getA());
}
}
}
上面的代码中,我们在持有锁的情况下调用了外部的方法,这是非常危险的(可能发生死锁)。为了避免这种危险的情况发生,我们使用开放调用。如果调用某个外部方法时不需要持有锁,我们称之为开放调用。
总结 综上,是常见的3种死锁的类型。即:静态的锁顺序死锁,动态的锁顺序死锁,协作对象之间的死锁。在写代码时,要确保线程在获取多个锁时采用一致的顺序。同时,要避免在持有锁的情况下调用外部方法。
推荐阅读
- 宽容谁
- 我要做大厨
- 增长黑客的海盗法则
- 画画吗()
- 2019-02-13——今天谈梦想()
- 远去的风筝
- 三十年后的广场舞大爷
- 叙述作文
- 20190302|20190302 复盘翻盘
- 学无止境,人生还很长