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
那么,基于以下定义:
死锁是指两个或多个竞争行为各自等待另一个完成的情况.
我会说答案是肯定的 - 确定一个线程可以无限期地等待某些东西,但是除非两个竞争行为在等待彼此,否则它根本不是死锁.
除非有人向我解释一个线程如何同时等待两个动作完成?
更新: 我能想到的唯一可能的情况是某种消息泵,其中一个线程处理一条消息,要求它无限期地等待某事发生,事实上,消息泵上的另一条消息将处理某些事情.
这种(令人难以置信的设计)场景在技术上可能被称为死锁.
Jon*_*eet 19
这完全取决于"死锁"的含义.例如,你可以很容易地wait()在显示器上没有任何东西可以脉冲...但我不认为我会称之为死锁.
如果您的服务器只运行一定数量的线程,那么根据您自己的"调用自身的方法"行,他们可能会忙着等待来自同一服务器的响应,如果这很重要的话.(最简单的例子:服务器只使用一个线程进行处理.如果你编写一个调用同一服务器的请求处理程序,它将等待被阻塞的线程完成处理请求,然后才能提供相同的请求......)这实际上并不是一种"同步阻塞"的僵局,但它确实存在危险.
编辑:要将此答案应用于其他人的定义,此处的竞争操作将是"完成当前请求"和"处理新请求".每个动作都在等待另一个动作发生.
Ale*_*yak 10
也许他的意思是LOCK本身,这当然太容易了:
synchronized( this )
{
wait( );
}
Run Code Online (Sandbox Code Playgroud)
从读锁升级到写锁(尝试在保持读锁时获取写锁)将导致线程完全被阻塞.这是一个僵局吗?你是判断者...但这是用单个线程创建效果的最简单方法.
http://download.oracle.com/javase/6/docs/api/java/util/concurrent/locks/ReentrantReadWriteLock.html
死锁是资源饥饿的一种形式,具有多个线程之间的交互.
当一个线程进入资源自身的状态时,它被称为一个类似于死锁的活锁,但是根据定义它不一样.
活锁的一个例子是使用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)
一个相关的问题是; 一个线程可以在不创建额外线程的情况下陷入死锁.这是可能的,因为有后台线程,例如终结器线程,它可以在后台运行用户代码.这允许主线程和终结器线程相互死锁.
根据维基百科的说法,"僵局是一种情况,其中两个或更多的竞争行动都在等待另一个完成,因此两者都没有."
......"在计算机科学中,Coffman死锁指的是当两个或多个进程各自等待释放资源,或者两个以上的进程在循环链中等待资源时的特定条件."
如果你对定义严格要求,我认为这里有两个或两个以上的关键词.
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)
这表明该线程确实已成功锁定自己