Java死锁示例
2019-11-24 本文已影响0人
nzdxwl
以下是Java中死锁的两个示例,一个是同步代码块嵌套,一个是同步方法互相调用。
public class DeadLockDemo {
static void sleep(int seconds) {
try {
TimeUnit.SECONDS.sleep(seconds);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/* 示例一:同步代码块嵌套 */
static void demo1() {
//相当于资源1和资源2
Integer a1 = new Integer(1);
Integer a2 = new Integer(2);
//两个次序相反的迭代器
Iterator<Integer> it = Arrays.asList(a1,a2).iterator();
Iterator<Integer> it2 = Arrays.asList(a2,a1).iterator();
//两个线程同时执行
new Thread(()-> {new DeadLockDemo().accessResource(it);}).start();
new Thread(()-> {new DeadLockDemo().accessResource(it2);}).start();
}
//demo1示例所用方法,传入一个资源迭代器,获取每个资源后上锁并迭代处理后续资源
public void accessResource(Iterator it) {
if(it.hasNext()) {
Object o = it.next();
System.out.println(Thread.currentThread().getName() + " --- waiting for lock ---" + o);
synchronized(o) {
System.out.println(Thread.currentThread().getName() + " --- hold lock ---" + o);
sleep(2);
accessResource(it);
}
}
}
/* 示例二:互相调用 */
static void demo2() {
DeadLockDemo mdl = new DeadLockDemo();
ClassA a = mdl.new ClassA();
ClassB b = mdl.new ClassB();
//一个线程调用a的同步方法,并传入b,在a方法中调用b的同步方法
new Thread(()-> {a.handleClassB(b);}).start();
//另外个线程则调用b的同步方法,传入a,在b方法中调用a的同步方法
new Thread(()-> {b.handleClassA(a);}).start();
}
//同步方法中休眠1秒钟使得两个线程都有足够的时间获取到调用类的锁,否则可能a和b的锁都被一个线程获得,这样两个线程先后都能完成不会死锁
class ClassA {
public synchronized void handleClassB(ClassB b) {
System.out.println("A handle B...");
sleep(1);
b.doSomething();
}
public synchronized void doSomething() { System.out.println("A processing");}
}
class ClassB{
public synchronized void handleClassA(ClassA a) {
System.out.println("B handle A...");
sleep(1);
a.doSomething();
}
public synchronized void doSomething() {System.out.println("B processing"); }
}
public static void main(String[] args) {
// demo1();
demo2();
}
示例说明
同步代码块嵌套
这个例子是假设线程A要处理一系列资源,假设资源按照1,2,3的顺序保存在列表中,线程A调用同步方法逐个获取资源,并加锁后进行处理,如果资源未处理完,则进行迭代操作;那么如果有线程B也是要处理资源,获得的资源列表中包含线程A处理的资源,并且顺序与线程A相反,当线程B也进行同样的操作时,那么就有可能发生死锁。
同步方法互相调用
这个例子是线程1调用类A实例的同步方法,获得类A实例的锁,并在同步方法中调用类B的同步方法,
与此同时,线程2则调用类B实例的同步方法,获得类B实例的锁,并在同步方法中调用类A的同步方法;当两个线程都获得第一个锁时,再去获取第二个锁就产生了死锁。下面例子用同个类的方法互调来产生死锁,原理与示例二一样,代码相对简洁但没示例二的好理解,且一旦只有一个线程获得两个锁时,会出现栈溢出错误。
/* 同类互调 */
static void demo3() {
DeadLockDemo mdl1 = new DeadLockDemo();
DeadLockDemo mdl2 = new DeadLockDemo();
new Thread(()->{mdl1.processOther(mdl2);}).start();
new Thread(()->{mdl2.processOther(mdl1);}).start();
}
public synchronized void processOther(DeadLockDemo mdl) {
System.out.println(Thread.currentThread().getName() + ": hold " + this + "'s lock...");
sleep(1);
mdl.processOther(this);
}