Как использовать wait и notify в Java без IllegalMonitorStateException?
У меня есть 2 матрицы, и мне нужно их перемножить, а затем распечатать результаты для каждой ячейки. Как только одна ячейка будет готова, мне нужно ее распечатать, но, например, мне нужно напечатать ячейку [0] [0] перед ячейкой [2] [0], даже если результат [2] [0] готов первым. Итак, мне нужно распечатать это по порядку. Итак, моя идея состоит в том, чтобы заставить поток принтера ждать, пока multiplyThread
уведомит его, что правильная ячейка готова к печати, а затем printerThread
распечатает ячейку и вернется к ожиданию и так далее..
Итак, у меня есть этот поток, который выполняет умножение:
public void run()
{
int countNumOfActions = 0; // How many multiplications have we done
int maxActions = randomize(); // Maximum number of actions allowed
for (int i = 0; i < size; i++)
{
result[rowNum][colNum] = result[rowNum][colNum] + row[i] * col[i];
countNumOfActions++;
// Reached the number of allowed actions
if (countNumOfActions >= maxActions)
{
countNumOfActions = 0;
maxActions = randomize();
yield();
}
}
isFinished[rowNum][colNum] = true;
notify();
}
Поток, который печатает результат для каждой ячейки:
public void run()
{
int j = 0; // Columns counter
int i = 0; // Rows counter
System.out.println("The result matrix of the multiplication is:");
while (i < creator.getmThreads().length)
{
synchronized (this)
{
try
{
this.wait();
}
catch (InterruptedException e1)
{
}
}
if (creator.getmThreads()[i][j].getIsFinished()[i][j] == true)
{
if (j < creator.getmThreads()[i].length)
{
System.out.print(creator.getResult()[i][j] + " ");
j++;
}
else
{
System.out.println();
j = 0;
i++;
System.out.print(creator.getResult()[i][j] + " ");
}
}
}
Теперь он выдает мне эти исключения:
Exception in thread "Thread-9" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-6" Exception in thread "Thread-4" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at multiplyThread.run(multiplyThread.java:49)
java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-5" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-8" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-7" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-11" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-10" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at multiplyThread.run(multiplyThread.java:49)
Exception in thread "Thread-12" java.lang.IllegalMonitorStateException
at java.lang.Object.notify(Native Method)
at multiplyThread.run(multiplyThread.java:49)
строка 49 в multiplyThread
- это "notify()".. Я думаю, мне нужно использовать synchronized по-другому, но я не уверен, как.
Если кто-нибудь может помочь этому коду работать, я буду очень признателен.
Переведено автоматически
Ответ 1
Чтобы иметь возможность вызывать notify(), вам необходимо выполнить синхронизацию на одном объекте.
synchronized (someObject) {
someObject.wait();
}
/* different thread / object */
synchronized (someObject) {
someObject.notify();
}
Ответ 2
При использовании методов wait
и notify
or notifyAll
в Java необходимо помнить следующее:
- Используйте
notifyAll
вместоnotify
, если вы ожидаете, что более одного потока будут ожидать блокировки. - Методы
wait
иnotify
должны вызываться в синхронизированном контексте. Смотрите ссылку для более подробного объяснения. - Всегда вызывайте
wait()
метод в цикле, потому что, если несколько потоков ожидают блокировки, и один из них получил блокировку и сбросил условие, тогда другим потокам необходимо проверить условие после пробуждения, чтобы увидеть, нужно ли им снова ждать или они могут начать обработку. - Используйте один и тот же объект для вызова
wait()
иnotify()
метода; у каждого объекта есть своя блокировка, поэтому вызовwait()
объекта A иnotify()
объекта B не будет иметь никакого смысла.
Ответ 3
Вам вообще нужно это выполнять? Мне интересно, насколько велики ваши матрицы и есть ли какая-либо выгода в том, что один поток печатает, пока другой выполняет умножение.
Возможно, стоило бы измерить это время, прежде чем выполнять относительно сложную потоковую работу?
Если вам действительно нужно выполнить потоковое преобразование, я бы создал 'n' потоков для выполнения умножения ячеек (возможно, 'n' - это количество доступных вам ядер), а затем использовал механизмы ExecutorService и Future для отправки нескольких умножений одновременно.
Таким образом, вы можете оптимизировать работу в зависимости от количества ядер, и вы используете инструменты Java threading более высокого уровня (что должно упростить жизнь). Запишите результаты обратно в принимающую матрицу, а затем просто распечатайте это, как только все ваши будущие задачи будут выполнены.
Ответ 4
Допустим, у вас есть приложение "черный ящик" с некоторым классом по имени, BlackBoxClass
у которого есть метод doSomething();
.
Кроме того, у вас есть наблюдатель или слушатель с именем, onResponse(String resp)
который будет вызван BlackBoxClass
через неизвестное время.
Процесс прост:
private String mResponse = null;
...
BlackBoxClass bbc = new BlackBoxClass();
bbc.doSomething();
...
@override
public void onResponse(String resp){
mResponse = resp;
}
Допустим, мы не знаем, что происходит с BlackBoxClass
и когда мы должны получить ответ, но вы не хотите продолжать свой код, пока не получите ответ или, другими словами, не получите onResponse
вызов. Здесь вводится "Помощник синхронизации":
public class SyncronizeObj {
public void doWait(long l){
synchronized(this){
try {
this.wait(l);
} catch(InterruptedException e) {
}
}
}
public void doNotify() {
synchronized(this) {
this.notify();
}
}
public void doWait() {
synchronized(this){
try {
this.wait();
} catch(InterruptedException e) {
}
}
}
}
Теперь мы можем реализовать то, что хотим:
public class Demo {
private String mResponse = null;
...
SyncronizeObj sync = new SyncronizeObj();
public void impl(){
BlackBoxClass bbc = new BlackBoxClass();
bbc.doSomething();
if(mResponse == null){
sync.doWait();
}
/** at this momoent you sure that you got response from BlackBoxClass because
onResponse method released your 'wait'. In other cases if you don't want wait too
long (for example wait data from socket) you can use doWait(time)
*/
...
}
@override
public void onResponse(String resp){
mResponse = resp;
sync.doNotify();
}
}