多线程Java同步列表死锁
摘自生效的Java第二版第67项第266-268页:
The background thread calls
s.removeObserver
, which attempts to lock observers, but it can’t acquire the lock, because the main thread already has the lock. All the while, the main thread is waiting for the background thread to finish removing the observer, which explains the deadlock.
我试图通过使用ThreadMXBean(Programmatic deadlock detection in java)找出main方法中哪些线程死锁,但是为什么它不返回死锁的线程呢? 我使用了一个新线程来运行ThreadMXBean检测
public class ObservableSet<E> extends ForwardingSet<E> {
public ObservableSet(Set<E> set) { super(set); }
private final List<SetObserver<E>> observers =
new ArrayList<SetObserver<E>>();
public void addObserver(SetObserver<E> observer) {
synchronized(observers) {
observers.add(observer);
}
}
public boolean removeObserver(SetObserver<E> observer) {
synchronized(observers) {
return observers.remove(observer);
}
}
private void notifyElementAdded(E element) {
synchronized(observers) {
for (SetObserver<E> observer : observers)
observer.added(this, element);
}
}
@Override
public boolean add(E element) {
boolean added = super.add(element); if (added)
notifyElementAdded(element); return added;
}
@Override
public boolean addAll(Collection<? extends E> c) {
boolean result = false; for (E element : c)
result|=add(element); //callsnotifyElementAdded
return result;
}
public static void main(String[] args) {
ObservableSet<Integer> set =
new ObservableSet<Integer>(new HashSet<Integer>());
final ThreadMXBean threadMxBean = ManagementFactory.getThreadMXBean();
Thread t = new Thread(new Runnable() {
@Override
public void run() {
while( true ) {
long [] threadIds = threadMxBean.findDeadlockedThreads();
if( threadIds != null) {
ThreadInfo[] infos = threadMxBean.getThreadInfo(threadIds);
for( ThreadInfo threadInfo : infos) {
StackTraceElement[] stacks = threadInfo.getStackTrace();
for( StackTraceElement stack : stacks ) {
System.out.println(stack.toString());
}
}
}
try {
System.out.println("Sleeping..");
TimeUnit.MILLISECONDS.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
});
t.start();
set.addObserver(new SetObserver<Integer>() {
public void added(ObservableSet<Integer> s, Integer e) {
ExecutorService executor = Executors.newSingleThreadExecutor();
final SetObserver<Integer> observer = this; try {
executor.submit(new Runnable() {
public void run() {
s.removeObserver(observer);
} }).get();
} catch (ExecutionException ex) {
throw new AssertionError(ex.getCause());
} catch (InterruptedException ex) {
throw new AssertionError(ex.getCause());
} finally {
executor.shutdown();
}
}
});
for (int i = 0; i < 100; i++)
set.add(i);
}
}
public interface SetObserver<E> {
// Invoked when an element is added to the observable set
void added(ObservableSet<E> set, E element);
}
// ForwardingSet<E> simply wraps another Set and forwards all operations to it.
# 1 楼答案
你确定会发生死锁吗? 尝试使用以下更改运行程序:
1)移除观察者时添加日志消息:
2)将死锁检测线程标记为守护进程:
我的猜测是,僵局可能不会发生
# 2 楼答案
你陷入了僵局
但是,您没有一个循环,这就是ThreadMXBean#findDeadlockedThreads方法所搜索的循环。从javadoc:
在本例中,主线程正在等待将来的结果。而另一个线程(不持有锁)正在等待主线程释放其锁