我已经创建了两个示例类,请忽略像通过get(1L)访问Map这样的怪癖。我以一种非常简单的方式重新创建了我在实际项目中的数据结构,因为我正在努力唤醒线程。
首先是MyThread类。它所做的就是创建一个线程,创建一个Handler示例,并将线程传递给Handler,然后通过join()等待线程。线程所做的就是等待。它是在“this”上同步的,我假设它是线程的示例(匿名内部类)。
public class MyThread {
public static void main(String[] args) {
MyThread t = new MyThread();
}
public MyThread() {
Thread t = new Thread() {
@Override
public void run() {
synchronized (this) {
try {
wait();
} catch (InterruptedException e) {
System.out.println("interrupted");
}
}
}
};
Handler handler = new Handler(t);
System.out.println("starting thread");
t.start();
try {
t.join();
System.out.println("joined! (woke up)");
} catch (InterruptedException e) {
System.out.println("MyThread interrupted");
}
}
}
Handler类有一个Map。每个键都有一组指定的线程。3次之后,处理程序应该通过“t.notify()”唤醒MyThread中的线程。我在同一台显示器上同步了,对吧?然而,在它通知MyThread中的线程之后,什么也没有发生。但是如果我将t.notify()改为t.interrupt(),它会中断等待的线程,并将该线程加入MyThread。我不知道为什么会这样,我希望得到一些澄清。
public class Handler {
NavigableMap<Long, Set<Thread>> map = new TreeMap<>();
public Handler(Thread t2) {
System.out.println("in Handler");
map.put(1L, new HashSet<>());
map.get(1L).add(t2);
Thread t = new Thread(new Runnable() {
int counter = 0;
@Override
public void run() {
try {
while (true) {
System.out.println("waiting: " + counter);
Thread.sleep(3000);
if (++counter == 3) {
for (Thread t : map.get(1L)) {
synchronized (t) {
System.out.println("notifying!");
t.notify();
System.out.println("notified!");
}
}
}
}
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
});
t.start();
}
}
我在这里看到了多个问题,它只是在不同的显示器上同步,但在这里我在“这个”上同步,然后是同一个示例,所以它应该是相同的,不?
请原谅所有的简化(例如无限循环),我只是想创建一个简单的可执行示例。
创建测试示例。我希望notify()会唤醒等待的线程。
1条答案
按热度按时间bakd9h0s1#
对我很有效。您应该删除争用条件。另外,您似乎正在使用相当多的对象,因此您很可能正在等待一个与您正在通知的对象不同的对象。如果唯一的变化是等待的中断,它应该工作。
正如注解中所指出的,notify只唤醒一个等待线程,如果我在同一个对象上添加另一个等待,那么notify不会释放其中一个等待线程。
所有线程都通过将
notify()
切换为notifyAll();
来释放这对于Thread来说尤其是个问题,因为它是非常公开的。至少你应该使用一个不全局用于同步的不同对象。