一个线程可能会死锁吗?

Pra*_*ram 59 java multithreading deadlock rmi

从技术上讲,Java中的线程是否可以自行解锁?

我在一段时间的采访中被问到这个问题并回答说这是不可能的,但面试官告诉我这是.不幸的是,我无法获得如何实现这种僵局的方法.

这让我思考,我能想到的唯一情况就是你可以实现这一点的地方就是你有一个RMI服务器进程,其中包含一个调用自身的方法.调用该方法的代码行放在synchronized块中.

这甚至可能还是面试官不正确?

我正在考虑的源代码是这些行(其中testDeadlock在RMI服务器进程中运行)

public boolean testDeadlock () throws RemoteException {
    synchronized (this) {
        //Call testDeadlock via RMI loopback            
    }
}
Run Code Online (Sandbox Code Playgroud)

Jus*_*tin 51

那么,基于以下定义:

死锁是指两个或多个竞争行为各自等待另一个完成的情况.

我会说答案是肯定的 - 确定一个线程可以无限期地等待某些东西,但是除非两个竞争行为在等待彼此,否则它根本不是死锁.

除非有人向我解释一个线程如何同时等待两个动作完成?

更新: 我能想到的唯一可能的情况是某种消息泵,其中一个线程处理一条消息,要求它无限期地等待某事发生,事实上,消息泵上的另一条消息将处理某些事情.

这种(令人难以置信的设计)场景在技术上可能被称为死锁.

  • +1.同意你需要两个探戈(我的意思是死锁),但只有1个悬挂自己. (24认同)
  • +1给Kragen解释,+1给亚历山大为tl; dr版本. (3认同)
  • 我会考虑一些涉及一个线程和消息泵的场景构成死锁.当前线程是一个'东西',消息队列是另一个; 主线程可能会等待队列中的消息执行主线程等待时不会发生的事情.如果消息队列支持优先级,则在处理低优先级消息之前处理消息时,可能会出现锁定情况,将以高优先级重新提取该消息. (2认同)

Jon*_*eet 19

这完全取决于"死锁"的含义.例如,你可以很容易地wait()在显示器上没有任何东西可以脉冲...但我不认为我会称之为死锁.

如果您的服务器只运行一定数量的线程,那么根据您自己的"调用自身的方法"行,他们可能会忙着等待来自同一服务器的响应,如果这很重要的话.(最简单的例子:服务器只使用一个线程进行处理.如果你编写一个调用同一服务器的请求处理程序,它将等待被阻塞的线程完成处理请求,然后才能提供相同的请求......)这实际上并不是一种"同步阻塞"的僵局,但它确实存在危险.

编辑:要将此答案应用于其他人的定义,此处的竞争操作将是"完成当前请求"和"处理新请求".每个动作都在等待另一个动作发生.

  • 还要考虑这个简单的案例`Thread.currentThread.join()` (2认同)

Ale*_*yak 10

也许他的意思是LOCK本身,这当然太容易了:

synchronized( this )
{
    wait( );
}
Run Code Online (Sandbox Code Playgroud)


fin*_*nnw 7

也许采访者想到的是:

Thread.currentThread().join();
Run Code Online (Sandbox Code Playgroud)

但是,我认为它不算是一个僵局.


sjl*_*lee 6

从读锁升级到写锁(尝试在保持读锁时获取写锁)将导致线程完全被阻塞.这是一个僵局吗?你是判断者...但这是用单个线程创建效果的最简单方法.

http://download.oracle.com/javase/6/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html


Pet*_*rey 6

死锁是资源饥饿的一种形式,具有多个线程之间的交互.

当一个线程进入资源自身的状态时,它被称为一个类似于死锁的活锁,但是根据定义它不一样.

活锁的一个例子是使用ReentrantReadWriteLock.尽管在读取或写入时可重入,但它不允许从读取到写入升级锁定.

public class LiveLock {
    public static void main(String[] args) {
        ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
        lock.readLock().lock();
        if (someCondition()) {
            // we want to write without allowing another thread to jump in.
            lock.writeLock().lock();
        }
    }

    private static boolean someCondition() {
        return true;
    }
}
Run Code Online (Sandbox Code Playgroud)

这导致进程阻塞

"main" #1 prio=5 os_prio=0 tid=0x0000000002a52800 nid=0x550c waiting on condition [0x000000000291f000]
   java.lang.Thread.State: WAITING (parking)
    at sun.misc.Unsafe.park(Native Method)
    - parking to wait for  <0x00000007162e5e40> (a java.util.concurrent.locks.ReentrantReadWriteLock$NonfairSync)
    at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireQueued(AbstractQueuedSynchronizer.java:870)
    at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquire(AbstractQueuedSynchronizer.java:1199)
    at java.util.concurrent.locks.ReentrantReadWriteLock$WriteLock.lock(ReentrantReadWriteLock.java:943)
    at LiveLock.main(LiveLock.java:10)
Run Code Online (Sandbox Code Playgroud)

一个相关的问题是; 一个线程可以在不创建额外线程的情况下陷入死锁.这是可能的,因为有后台线程,例如终结器线程,它可以在后台运行用户代码.这允许主线程和终结器线程相互死锁.


gui*_*ng5 5

根据维基百科的说法,"僵局是一种情况,其中两个或更多的竞争行动都在等待另一个完成,因此两者都没有."

......"在计算机科学中,Coffman死锁指的是当两个或多个进程各自等待释放资源,或者两个以上的进程在循环链中等待资源时的特定条件."

如果你对定义严格要求,我认为这里有两个或两个以上的关键词.


Pra*_*ram 3

JVM 仅跟踪具有监视器的本地线程,如果调用类对自身进行外部回调,则传入调用会导致原始线程自身死锁。

您应该能够运行此代码来说明这个想法

import java.rmi.*;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.rmi.server.*;

public class DeadlockThreadExample {

    public static interface DeadlockClass extends Remote {
        public void execute() throws RemoteException;
    }

    public static class DeadlockClassImpl extends UnicastRemoteObject implements DeadlockClass {
        private Object lock = new Object();

        public DeadlockClassImpl() throws RemoteException {
            super();
        }

        public void execute() throws RemoteException {
            try {
                System.out.println("execute()::start");

                synchronized (lock) {
                    System.out.println("execute()::Entered Lock");
                    DeadlockClass deadlockClass = (DeadlockClass) Naming.lookup("rmi://localhost/DeadlockClass");
                    deadlockClass.execute();
                }
                System.out.println("execute()::Exited Lock");
            } catch (NotBoundException e) {
                System.out.println(e.getMessage());
            } catch (java.net.MalformedURLException e) {
                System.out.println(e.getMessage());
            }
            System.out.println("execute()::end");
        }
    }

    public static void main(String[] args) throws Exception {
        LocateRegistry.createRegistry(Registry.REGISTRY_PORT);
        DeadlockClassImpl deadlockClassImpl = new DeadlockClassImpl();
        Naming.rebind("DeadlockClass", deadlockClassImpl);
        DeadlockClass deadlockClass = (DeadlockClass) Naming.lookup("rmi://localhost/DeadlockClass");
        deadlockClass.execute();
        System.exit(0);
    }
}
Run Code Online (Sandbox Code Playgroud)

程序的输出看起来像

execute()::start
execute()::Entered Lock
execute()::start
Run Code Online (Sandbox Code Playgroud)

此外,线程转储还显示以下内容

"main" prio=6 tid=0x00037fb8 nid=0xb80 runnable [0x0007f000..0x0007fc3c]
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.read(SocketInputStream.java:129)
    at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
    at java.io.BufferedInputStream.read(BufferedInputStream.java:235)
    - locked <0x02fdc568> (a java.io.BufferedInputStream)
    at java.io.DataInputStream.readByte(DataInputStream.java:241)


"RMI TCP Connection(4)-172.17.23.165" daemon prio=6 tid=0x0ad83d30 nid=0x1590 waiting for monitor entry [0x0b3cf000..0x0b3cfce8]
    at DeadlockThreadExample$DeadlockClassImpl.execute(DeadlockThreadExample.java:24)
    - waiting to lock <0x0300a848> (a java.lang.Object)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)


"RMI TCP Connection(2)-172.17.23.165" daemon prio=6 tid=0x0ad74008 nid=0x15f0 runnable [0x0b24f000..0x0b24fbe8] 
    at java.net.SocketInputStream.socketRead0(Native Method)
    at java.net.SocketInputStream.read(SocketInputStream.java:129)
    at java.io.BufferedInputStream.fill(BufferedInputStream.java:218)
    at java.io.BufferedInputStream.read(BufferedInputStream.java:235)
    - locked <0x02ffb6d8> (a java.io.BufferedInputStream)
    at java.io.DataInputStream.readByte(DataInputStream.java:241)
Run Code Online (Sandbox Code Playgroud)

这表明该线程确实已成功锁定自己

  • *如果调用类对自身进行外部回调,则传入的调用会导致原始线程自身死锁。*这是不正确的;它们是 2 个(或者更多,事实上)独立的线程。线程不能自己陷入僵局,面试官是个白痴,仅此而已。 (4认同)
  • 你回答了你自己的问题吗? (2认同)