与Java中的互斥体相关的问题

Nic*_*son 0 java multithreading

我试图理解多线程编程的概念.我知道死锁和互斥锁的概念,但我无法找到以下问题的答案.使用互斥锁时如何出现死锁问题?

Zar*_*nen 5

这是一个如何在Java中引发死锁的具体示例.我们产生了两个线程.第一个获取互斥锁a,然后等待一秒,然后尝试获取锁定b.第二个获得锁定b,然后等待,然后尝试获取a.结果是程序进入死锁并永远运行.

public class Deadlock {
    public static void main(String[] args) {
        final Object a = new Object();
        final Object b = new Object();
        new Thread() {
            @Override
            public void run() {
                synchronized (a) {
                    /* wait for a second to make it likely the other thread can acquire b */
                    try { Thread.sleep(1000); } catch (Exception e) {  }
                    synchronized (b) {
                        System.out.println("Acquired a, then b.");
                    }
                }
            }
        }.start();
        new Thread() {
            @Override
            public void run() {
                synchronized (b) {
                    /* wait for a second to make it likely the other thread can acquire a */
                    try { Thread.sleep(1000); } catch (Exception e) {  }
                    synchronized (a) {
                        System.out.println("Acquired b, then a.");
                    }
                }
            }
        }.start();
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,此代码不保证进入死锁.线程调度程序完全在其在第二个线程上启动之前运行第一个线程完成的权限,反之亦然.由于此示例中的等待时间很长,因此系统将进入死锁状态,但是如果不是休眠一秒钟,两个线程都会在每次锁定获取之前对可变时间长度进行一些计算,以下任何一项事情可能随机发生:

  • 僵局
  • "Acquired a, then b.", 其次是 "Acquired b, then a."
  • "Acquired b, then a.", 其次是 "Acquired a, then b."

你如何防止这种情况发生?

  • 只要你能逃脱它,就完全避免使用线程.
  • 不是在线程之间共享资源,而是让每个线程对自己的数据进行操作,并相互发送不可变消息.
  • 如果绝对必须使用共享资源,请尽量减少使用的互斥锁的数量.如果所有内容在同一对象上同步,则只有一个互斥锁,并且不会发生死锁.
  • 如果绝对必须有许多互斥锁,并且线程获取它们的组合,请执行以下操作:编写一个定义锁的总排序的函数.然后,每当您需要执行涉及多个互斥锁的操作时,请创建所涉及的互斥锁列表,对它们进行排序,然后在操作开始时按排序顺序输入它们.

看看java.util.concurrent包.它包含许多好吃的东西,可以处理许多真正有毛的东西.

另外,我不能夸大线程在意想不到的地方切换的程度.一个常见的错误是逐行查看每个线程,并想象线路可以交错的不同方式.但这还不够:一个线程可能会在某个库深处的某个嵌套函数调用中被切换出来.