java - 同步方法以避免死锁

标签 java multithreading deadlock synchronized locks

我有两个同步方法,并且正在使用中介器设计模式。 我试图避免死锁,这是(根据我的理解)例如,当一个线程锁定了变量 res1 但需要锁定变量 res2 时。另一个线程需要 res1 的锁,但拥有 res2 的锁 - 导致死锁,对吧?

假设我对死锁的理解是正确的,那么我的问题是我是否已经解决了这段代码中的死锁问题?

我有两个同步方法和两个线程。

public class Producer extends Thread {
    private Mediator med;
    private int id;
    private static int count = 1;

    public Producer(Mediator m) {
        med = m;
        id = count++;
    }

    public void run() {
        int num;
        while(true) {
            num = (int)(Math.random()*100);
            med.storeMessage(num);
            System.out.println("P-" + id + ": " + num);
        }
    }
}
<小时/>
public class Consumer extends Thread {
    private Mediator med;
    private int id;
    private static int count = 1;

    // laver kopling over til mediator
    public Consumer(Mediator m) {
        med = m;
        id = count++;
    }

    public void run() {
        int num;
        while(true) {
            num = med.retrieveMessage();
            System.out.println("C" + id + ": " + num);
        }
    }
}
<小时/>
public class Mediator {
    private int number;
    private boolean slotFull = false;

    public synchronized void storeMessage(int num) {
        while(slotFull == true) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }  
        slotFull = true;
        number = num;
        notifyAll();
    }

    public synchronized int retrieveMessage() {
        while(slotFull == false) {
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        slotFull = false;
        notifyAll();
        return number;
    }
}
<小时/>
public class MediatorTest {
    public static void main(String[] args) {
        Mediator mb = new Mediator(); 
        new Producer(mb).start();
        new Producer(mb).start();
        new Producer(mb).start();

        new Consumer(mb).start();
        new Consumer(mb).start();
    }
}

最佳答案

for example when a thread has a lock on a variable res1 but needs a lock on variable res2

重要的不是有两个变量,重要的是必须有两个(或更多)

名称“res1”和“res2”意味着两个资源,每个资源都可以有一个或多个变量,并且每个资源都有自己的锁。这就是你遇到麻烦的地方:

final Object lock1 = new Object();
final Object lock2 = new Object();

public void method1() {
    synchronized (lock1) {
        // Call Thread.sleep(1000) here to simulate the thread losing its time slice.
        synchronized(lock2) {
            doSomethingThatRequiresBothLocks
        }
    }
}

public void method2() {
    synchronized (lock2) {
        // Do the same here 'cause you can't know which thread will get to run first.
        synchronized(lock1) {
            doSomethingElseThatRequiresBothLocks()
        }
    }
}

如果线程A调用method1(),那么它在成功加锁后,有极小概率会丢失其时间片(即转向运行) lock1,但在锁定lock2之前。

然后,当线程 A 等待再次运行时,线程 B 调用 method2()。线程 B 将能够锁定 lock2,但随后它会卡住,因为 lock1 已被线程 A 锁定。此外,当线程 A 再次运行时,它会立即被锁定。当它尝试锁定线程 B 拥有的 lock2 时被阻止。两个线程都无法从该点继续。

<小时/>

在实际代码中,它从来没有那么明显。当它在现实生活中发生时,通常是因为来自两个或多个不同模块的代码之间存在一些不可预见的交互,这些模块甚至可能不知道彼此,但访问相同的公共(public)资源。

关于java - 同步方法以避免死锁,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30652678/

相关文章:

java - Camel可以用Reactor代替吗,如果可以,那么如何正确完成呢?

Java 直方图均衡化 - 无法从图像栅格中获取像素

java - 具有多个值的枚举具有描述

c# - 如何在非 UI 线程中使用 reg-free COM?

c++ - 使用 move 语义在构造函数中初始化类成员

java - 如何可靠地创建和检测线程死锁

database - 数据库如何锁定行并释放它们?

java - Action 事件停止

c++ - boost::system::error_code::message() 使用 boost::asio 套接字抛出访问冲突异常

c# - 如何在异步方法的单元测试中测试 ConfigureAwait(false)?