Из Effective Java, 2-е издание, стр. 67, стр. 266-268:
Фоновый поток вызывает s.removeObserver
, который пытается заблокировать наблюдателей, но не может получить блокировку, потому что основной поток уже имеет блокировку. Все это время основной поток ожидает, пока фоновый поток завершит удаление наблюдателя, что объясняет тупик.
Я пытаюсь выяснить, какие потоки взаимоблокированы в основном методе, используя ThreadMXBean ( Программное обнаружение взаимоблокировок в java ), но почему он не возвращает заблокированные потоки?
Я использовал новый поток для запуска обнаружения 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.