Ожидание и уведомление Java: IllegalMonitorStateException
Я не совсем понимаю как wait
а также notify
(из Object
) работать, и в результате я вынужден ограничить свои попытки в следующем разделе кода.
Main.java:
import java.util.ArrayList;
class Main
{
public static Main main = null;
public static int numRunners = 4;
public static ArrayList<Runner> runners = null;
public static void main(String[] args)
{
main = new Main();
}
Main()
{
runners = new ArrayList<Runner>(numRunners);
for (int i = 0; i < numRunners; i++)
{
Runner r = new Runner();
runners.add(r);
new Thread(r).start();
}
System.out.println("Runners ready.");
notifyAll();
}
}
Runner.java:
class Runner implements Runnable
{
public void run()
{
try
{
Main.main.wait();
} catch (InterruptedException e) {}
System.out.println("Runner away!");
}
}
В настоящее время я получаю IllegalMonitorStateException при вызове Main.main.wait();
но я не понимаю почему. Из того, что я вижу, мне нужно синхронизировать Runner.run
, но при этом я предполагаю, что он будет уведомлять только один поток, когда идея состоит в том, чтобы уведомить их всех.
Я смотрел на java.util.concurrent
, но я не могу найти подходящую замену (может быть, я просто что-то упустил).
2 ответа
Ты не можешь wait()
на объекте, если текущий поток не владеет монитором этого объекта. Для этого вы должны synchronize
в теме:
class Runner implements Runnable
{
public void run()
{
try
{
synchronized(Main.main) {
Main.main.wait();
}
} catch (InterruptedException e) {}
System.out.println("Runner away!");
}
}
То же правило относится к notify()
/ notifyAll()
также.
Javadocs для wait()
упомянуть это:
Этот метод должен вызываться только потоком, который является владельцем монитора этого объекта. Увидеть
Броски:notify
метод описания способов, с помощью которых поток может стать владельцем монитора.
IllegalMonitorStateException
- если текущий поток не является владельцем монитора этого объекта.
И из notify()
:
Поток становится владельцем монитора объекта одним из трех способов:
- Выполняя синхронизированный метод экземпляра этого объекта.
- Выполняя тело
synchronized
оператор, который синхронизируется на объекте.- Для объектов типа
Class
, выполняя синхронизированный статический метод этого класса.
Ты звонишь обоим wait
а также notifyAll
без использования synchronized
блок. В обоих случаях вызывающий поток должен иметь блокировку на мониторе, на котором вызывается метод.
Из документов для notify
(wait
а также notifyAll
иметь аналогичную документацию, но обратитесь к notify
для наиболее полного описания):
Этот метод должен вызываться только потоком, который является владельцем монитора этого объекта. Поток становится владельцем монитора объекта одним из трех способов:
- Выполняя синхронизированный метод экземпляра этого объекта.
- Выполняя тело синхронизированного оператора, который синхронизируется на объекте.
- Для объектов типа Class, выполняя синхронизированный статический метод этого класса.
Только один поток одновременно может владеть монитором объекта.
Только один поток сможет выйти wait
через некоторое время после notifyAll
поскольку им всем придется снова получить один и тот же монитор - но все будут уведомлены, поэтому, как только первый выйдет из синхронизированного блока, следующий получит блокировку и т. д.