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);
    }
上一篇 下一篇

猜你喜欢

热点阅读