有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java中单线程的多线程死锁

我读到单个用户线程可以与系统线程死锁 我的问题是,这个系统线程可以是任何与java线程共享资源的线程(不一定是java线程)。例如:锁定文件后对2个文件进行I/O操作。 因此,除非系统线程与java线程共享资源,否则它无法创建死锁。 是否有任何其他粗体的上述声明的例子

另一个问题:

如果有两个函数使用两个锁,则它们应以相同的顺序锁定。但是否必须以相同的相反顺序发布。两个功能的锁释放顺序是否不同 例如:

function1() {
   try {
    lock1.lock();
    lock2.lock();
   } finally {
     lock2.unlock();
     lock1.unlock();
   }
}

function2() {
   try {
    lock1.lock();
    lock2.lock();
   } finally {
     lock1.unlock();
     lock2.unlock();
   }
}

参考链接:if a single user thread deadlocks, a system thread must also be involved


共 (2) 个答案

  1. # 1 楼答案

    对于第一个问题:考虑任何Swing应用程序。例如,主线程可能很容易干扰事件分派线程(因为所有事件处理都发生在该特定线程中)。此外,您还可以使用终结器线程

    对于第二个问题:是的,您可以按任何顺序释放锁

  2. # 2 楼答案

    如果只涉及Java对象监视器锁,那么单个Java线程就不能对自身进行死锁,这是正确的

    现在还不完全清楚“系统线程”是什么意思。即使在运行一个简单的程序时,JVM也会有多个线程在运行,例如终结器线程,或者对于GUI应用程序,有一个事件分发线程(EDT)。这些线程可能会获得Java对象监视器锁,因此会针对单个应用程序线程死锁

    单个Java线程可以针对外部进程死锁,而不是其他Java线程。例如,考虑这个程序:

    public static void main(String[] args) throws Exception {
        Process proc = Runtime.getRuntime().exec("cat");
    
        byte[] buffer = new byte[100_000];
        OutputStream out = proc.getOutputStream();
        out.write(buffer);
        out.close();
    
        InputStream in = proc.getInputStream();
        int count = in.read(buffer);
        System.out.println(count);
    }
    

    这运行“cat”,它只是从stdin复制到stdout。这个程序通常会死锁,因为它会向子进程写入大量数据。子进程将阻止写入其输出,因为父进程尚未读取它。这会阻止子进程读取其所有输入。因此,Java线程与子进程之间出现了死锁。(处理这种情况的通常方法是让另一个Java线程读取子进程输出。)

    如果一个Java线程正在等待一个永远不会发生的通知,那么它可能会死锁。考虑:

    public static void main(String[] args) throws InterruptedException {
        Object obj = new Object();
        synchronized (obj) {
            obj.wait();
        }
    }
    

    这个程序永远不会终止,因为没有任何东西会通知obj或中断线程。这似乎有点做作,但在实践中确实会出现这种“唤醒丢失问题”。有bug的系统可能无法正确设置状态,或者在错误的时间调用notify,或者调用notify而不是notifyAll,导致线程在wait调用中被阻塞,等待永远不会发生的通知。在这种情况下,可能很难识别该线程死锁的另一个线程,因为该线程可能在过去已死亡,或者可能尚未创建。但这肯定是僵局

    更新

    我遇到了另一个单线程死锁的例子。Goetz等人,Java并发在实践中第215页,描述了线程饥饿死锁。考虑一个例子:

    a task that submits a task and waits for its result executes in a single-threaded Executor. In that case, the first task will wait forever, permanently stalling that task and all others waiting to execute in that Executor.

    (单线程Executor基本上是一个单线程,一次处理一个任务队列。)

    更新2

    我在文献中发现了另一个单线程死锁的例子:

    There are three patterns of pairwise deadlock that can occur using monitors. In practice, of course, deadlocks often involve more than two processes, in which case the actual patterns observed tend to be more complicated; conversely, it is also possible for a single process to deadlock with itself (for example, if an entry procedure is recursive).

    兰普森、巴特勒·W.和大卫·D·雷德尔在Mesa中使用流程和监控器的经验CACM第23卷第2期,1980年2月

    请注意,在本文中,“进程”指的是我们所说的线程,“进入过程”类似于同步方法。然而,在Mesa中,监视器不是可重入的,因此如果一个线程试图再次进入同一个监视器,它可能会死锁

    Posix线程也是如此。如果一个线程在一个正常(即非递归)互斥体上第二次调用pthread_mutex_lock,该线程将在自身上死锁

    从这些例子中,我得出结论,“死锁”并不严格要求两个或更多线程