從有效的Java第二版項目67 266-268頁:的Java同步列表僵局
後臺線程調用
s.removeObserver
,它試圖鎖定觀察員,但它不能獲取鎖,因爲主線程已經有鎖。一直以來,主線程都在等待後臺線程完成移除觀察者,這解釋了死鎖。
我想通過使用ThreadMXBean(Programmatic deadlock detection in java)找出主要方法中的哪個線程死鎖,但爲什麼它不返回死鎖的線程? 我使用了一個新的Thread來運行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.
發生死鎖,因爲「從觀察者身上移除」絕不會被打印出來。將線程設置爲守護進程並沒有幫助。什麼促使你說僵局沒有發生? – portoalet 2010-04-10 00:09:59
@portoalet我的錯!我把代碼扔到我的IDE中,運行它,但是我運行的代碼稍有不同 - 我在removeObserver調用之前有了println *,並且它被執行了 - 我錯誤地跳到了死鎖沒有發生的結論。再次抱歉! – 2010-04-10 02:03:29