JUC并发相关

5. 并发终结之线程活性故障

2020-10-01  本文已影响0人  涣涣虚心0215

线程除了上下文切换导致RUNNABLE和非RUNNABLE状态的切换,还有程序自身错误导致线处于RUNNABLE但是任务没有进展,这种现象称为线程活性故障
常见的活性故障:

class Test{
    private final Object object1 = new Object();
    private final Object object2 = new Object();
    public void test1() throws InterruptedException {
        synchronized (object1){
            System.out.println(Thread.currentThread().getName()+"==="+"Take lock 1....");
            Thread.sleep(2000);
            synchronized (object2){
                System.out.println(Thread.currentThread().getName()+"==="+"Take lock 2...");
            }
        }
    }
    public void test2()throws InterruptedException {
        synchronized (object2){
            System.out.println(Thread.currentThread().getName()+"==="+"Take lock 2....");
            Thread.sleep(2000);
            synchronized (object1){
                System.out.println(Thread.currentThread().getName()+"==="+"Take lock 1...");
            }
        }
    }
}

除此特征之外,死锁还有另外一种特征,比如ClassA有同步方法synchronizedA()和synchronizedB(),ClassB有同步方法synchronizedC()和synchronizedD()。如果synchronizedA()方法调用了synchronizedC(),而synchronizedD()调用了synchronizedB(),这时候一个线程执行ClassA.SynchronizedA()时,另一个线程执行ClassB.SynchronizedD(),那么这两个线程也有可能产生死锁。

class ClassA {
    private ClassB classB;
    public ClassB getClassB() {
        return classB;
    }
    public void setClassB(ClassB classB) {
        this.classB = classB;
    }
    public synchronized void testA1() throws InterruptedException {
        System.out.println(Thread.currentThread().getName() + "===" + "Take A1....");
        classB.testB1();
    }
    public synchronized void testA2() throws InterruptedException {
        System.out.println(Thread.currentThread().getName() + "===" + "Take A2...");
    }
}

class ClassB {
    private ClassA classA;
    public ClassA getClassA() {
        return classA;
    }
    public void setClassA(ClassA classA) {
        this.classA = classA;
    }
    public synchronized void testB1() throws InterruptedException {
        System.out.println(Thread.currentThread().getName() + "===" + "Take B1....");
    }
    public synchronized void testB2() throws InterruptedException {
        System.out.println(Thread.currentThread().getName() + "===" + "Take B2...");
        classA.testA2();
    }
}
------------------
main
Thread thread1 = new Thread(() -> {
    try {
        classA.testA1();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
});
Thread thread2 = new Thread(() -> {
    try {
        classB.testB2();
    } catch (InterruptedException e) {
        e.printStackTrace();
    }
});

受保护方法monitorY.wait()会释放锁,但是释放的是monitorY对应的锁,而monitorX锁还是一直占着(只有monitorY被唤醒才能释放monitorX);此时通知线程需要调用monitorY.notifyAll()能够唤醒等待线程需要持有相应的锁monitorY,但是monitorY的临界区是在monitorX里面,因此通知线层也需要持有monitorX的锁(此时被等待线程占用),导致通知线程无法调用monitorY.notifyAll()来唤醒等待线程。

class ClassA {
    private BlockingQueue queue = new ArrayBlockingQueue(1);
    private int processed = 0;
    private int accepted = 0;

//如果doProcess()正好take()阻塞了,则需要queue.put()生产者来唤醒,但是Synchronized锁被占用,导致accept
//获取不到锁,不能进行唤醒。
    public synchronized void doProcess() throws InterruptedException {
        String msg = (String)queue.take();
        System.out.println("==="+msg);
        processed ++;
    }
    public synchronized void accept(String msg) throws InterruptedException {
        queue.put(msg);
        accepted ++;
    }
}
----------------------------
 class Test {
    public static void main(String[] args) {
        Object monitorA = new Object();
        SharedObject sharedObject = new SharedObject();
        new Thread(() -> {
            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " start");
            synchronized (monitorA) {
                System.out.println(Thread.currentThread().getName() + " get lock a");
                while (!sharedObject.isFlag()) {
                    synchronized (sharedObject) {
                        System.out.println(Thread.currentThread().getName() + " get lock b");
                        try {
                            System.out.println(Thread.currentThread().getName() + " before wait");
                            sharedObject.wait();
                            System.out.println(Thread.currentThread().getName() + " after wait");
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                    System.out.println(Thread.currentThread().getName() + " after monitor b");
                }

            }
        }, "waitThread").start();
        new Thread(() -> {
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + " start");
            synchronized (monitorA) {
                System.out.println(Thread.currentThread().getName() + " get lock a");
                synchronized (sharedObject) {
                    System.out.println(Thread.currentThread().getName() + " get lock b");
                    sharedObject.setFlag(true);
                    sharedObject.notify();
                    System.out.println(Thread.currentThread().getName() + " after notify");
                }
            }
        }, "notifyThread").start();
    }
}
class SharedObject {
    public boolean isFlag() {
        return flag;
    }
    public void setFlag(boolean flag) {
        this.flag = flag;
    }
    private boolean flag = false;
}
=========从下面图可以看到notifyThread是处于BLOCKED状态,waitThread是处于WAITING状态。
waitThread start
waitThread get lock a
waitThread get lock b
waitThread before wait
notifyThread start
image.png
上一篇 下一篇

猜你喜欢

热点阅读