Я використовую для моєї програми багатопотокове передавання в java. Я успішно запустив нитку, але коли я використовую Thread.wait()
, вона кидає java.lang.IllegalMonitorStateException
. Як змусити нитку чекати, поки вона буде повідомлена?
Я використовую для моєї програми багатопотокове передавання в java. Я успішно запустив нитку, але коли я використовую Thread.wait()
, вона кидає java.lang.IllegalMonitorStateException
. Як змусити нитку чекати, поки вона буде повідомлена?
Відповіді:
Вам потрібно бути в synchronized
блоці, Object.wait()
щоб працювати.
Також я рекомендую подивитися пакети одночасності замість старих шкільних пакетів для нарізки. З ними безпечніше і простіше працювати .
Щасливе кодування.
EDIT
Я припускав, що ви маєте на увазі Object.wait()
як виняток те, що відбувається, коли ви намагаєтесь отримати доступ, не утримуючи блокування об'єктів.
wait
визначено в Object
, а не це Thread
. Увімкнений монітор Thread
трохи непередбачуваний.
Хоча всі об'єкти Java мають монітори, як правило, краще мати спеціальний замок:
private final Object lock = new Object();
Діагностику можна читати трохи простіше, за невеликої вартості пам’яті (близько 2 Кб на процес), використовуючи названий клас:
private static final class Lock { }
private final Object lock = new Lock();
Для того, щоб / wait
або об’єкт, вам потрібно тримати замок із заявою. Крім того, вам знадобиться цикл, щоб перевірити стан пробудження (знайдіть хороший текст на нитці, щоб пояснити, чому).notify
notifyAll
synchronized
while
synchronized (lock) {
while (!isWakeupNeeded()) {
lock.wait();
}
}
Повідомляти:
synchronized (lock) {
makeWakeupNeeded();
lock.notifyAll();
}
Варто розібратися в розумінні як мови Java, так і java.util.concurrent.locks
блокувань (і java.util.concurrent.atomic
) при вступі в багатопотоковість. Але використовуйте java.util.concurrent
структури даних, коли зможете.
wait
, так ви ніколи не потрапите notify
. Однак у документах API для Object.wait
"Нитка звільняє право власності на цей монітор". Тож у той час wait
, як ніби він знаходиться поза synchronized
блоками, що обгороджуються (для одного і того ж об'єкта можуть бути кілька synchronized
блоків на одному об'єкті).
Я знаю, що цій темі вже майже 2 роки, але все-таки потрібно закрити цю проблему, оскільки я також прийшов на цю сесію запитань з такою ж проблемою ...
Будь ласка, читайте це визначення незаконногоMonitorException знову і знову ...
IllegalMonitorException кидається, щоб вказати, що потік намагався чекати на моніторі об'єкта або сповіщати інші потоки, що очікують на моніторі об'єкта, не володіючи вказаним монітором.
Цей рядок знову і знову говорить, що IllegalMonitorException виникає, коли виникає одна з двох ситуацій ....
1> чекайте на моніторі об'єкта, не володіючи вказаним монітором.
2> повідомляти інші потоки, що очікують на моніторі об'єкта, не володіючи вказаним монітором.
Деякі, можливо, отримали свої відповіді ... хто все ні, тоді, будь ласка, перевірте 2 твердження ....
синхронізований (об'єкт)
object.wait ()
Якщо обидва об'єкти однакові ... тоді не може бути незаконнимMonitorException.
Тепер знову прочитайте визначення IllegalMonitorException, і ви його не забудете знову ...
На основі ваших коментарів звучить так, як ви робите щось подібне:
Thread thread = new Thread(new Runnable(){
public void run() { // do stuff }});
thread.start();
...
thread.wait();
Є три проблеми.
Як говорили інші, obj.wait()
його можна викликати лише у тому випадку, якщо поточна нитка містить примітивний замок / мьютекс для obj
. Якщо поточна нитка не містить блокування, ви отримуєте виняток, який ви бачите.
thread.wait()
Виклик не робити те , що ви , здається, чекаючи , що це зробити. Зокрема, thread.wait()
не змушує висунутий потік чекати. Швидше це викликає поточний потік не чекати , поки деякі інші виклики різьбовими thread.notify()
або thread.notifyAll()
.
Насправді немає безпечного способу змусити Thread
екземпляр зробити паузу, якщо він цього не хоче. (Найближчий до цього Java - це застарілий Thread.suspend()
метод, але цей метод за своєю суттю небезпечний, як це пояснено в Javadoc.)
Якщо ви хочете, щоб нещодавно почалася Thread
пауза, найкращий спосіб зробити це - створити CountdownLatch
екземпляр і запросити потік await()
на засувці, щоб призупинитись. Потім головна нитка закликає countDown()
засувку, щоб призупинена нитка продовжувалась.
Ортогональна попереднім точкам використання Thread
об'єкта як блокування / мютексу може спричинити проблеми. Наприклад, javadoc for Thread::join
каже:
Ця реалізація використовує цикл
this.wait
викликів, що обумовленіthis.isAlive
. По мірі завершення потокуthis.notifyAll
викликається метод. Рекомендується , щоб програми не використовуютьwait
,notify
абоnotifyAll
наThread
випадках.
Оскільки ви не опублікували код, ми наче працюємо в темряві. Які деталі винятку?
Ви викликаєте Thread.wait () зсередини потоку чи поза ним?
Я запитую це, оскільки згідно з даними javadoc для IllegalMonitorStateException, це:
Викинуто, щоб вказати, що потік намагався чекати на моніторі об'єкта або сповіщати інші потоки, що очікують на моніторі об'єкта, не володіючи вказаним монітором.
Щоб уточнити цю відповідь, цей дзвінок, який чекає на потоці, також викидає IllegalMonitorStateException, незважаючи на те, що викликається з синхронізованого блоку:
private static final class Lock { }
private final Object lock = new Lock();
@Test
public void testRun() {
ThreadWorker worker = new ThreadWorker();
System.out.println ("Starting worker");
worker.start();
System.out.println ("Worker started - telling it to wait");
try {
synchronized (lock) {
worker.wait();
}
} catch (InterruptedException e1) {
String msg = "InterruptedException: [" + e1.getLocalizedMessage() + "]";
System.out.println (msg);
e1.printStackTrace();
System.out.flush();
}
System.out.println ("Worker done waiting, we're now waiting for it by joining");
try {
worker.join();
} catch (InterruptedException ex) { }
}
wait()
.
worker.wait()
лінію? Тоді вам слід синхронізувати працівника, а не замку.
Щоб мати справу з IllegalMonitorStateException, ви повинні переконатися, що всі виклики методів очікування, повідомлення та notifyAll мають місце лише тоді, коли потоці виклику належить відповідний монітор . Найпростішим рішенням є включення цих дзвінків всередину синхронізованих блоків. Об'єктом синхронізації, який повинен викликатися у синхронізованому операторі, є той, чий монітор повинен бути придбаний.
Ось простий приклад для розуміння концепції монітора
public class SimpleMonitorState {
public static void main(String args[]) throws InterruptedException {
SimpleMonitorState t = new SimpleMonitorState();
SimpleRunnable m = new SimpleRunnable(t);
Thread t1 = new Thread(m);
t1.start();
t.call();
}
public void call() throws InterruptedException {
synchronized (this) {
wait();
System.out.println("Single by Threads ");
}
}
}
class SimpleRunnable implements Runnable {
SimpleMonitorState t;
SimpleRunnable(SimpleMonitorState t) {
this.t = t;
}
@Override
public void run() {
try {
// Sleep
Thread.sleep(10000);
synchronized (this.t) {
this.t.notify();
}
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
Виклик Thread.wait () має сенс всередині коду, який синхронізується на об'єкті Thread.class. Я не думаю, що це ви мали на увазі.
Ви запитаєте
Як змусити нитку чекати, поки вона буде повідомлена?
Ви можете змусити чекати лише поточну нитку. Будь-яку іншу нитку можна лише обережно попросити почекати, якщо вона погодиться.
Якщо ви хочете зачекати деяку умову, вам потрібен об’єкт блокування - об’єкт Thread.class - це дуже поганий вибір - це однотонний AFAIK, тому синхронізація на ньому (за винятком статичних методів потоку) небезпечна.
Деталі синхронізації та очікування вже пояснив Том Хоутін.
java.lang.IllegalMonitorStateException
означає, що ви намагаєтесь чекати об’єкта, на якому ви не синхронізовані - це робити незаконно.
Не впевнений, чи це допоможе комусь іншому чи ні, але це було ключовою частиною для вирішення моєї проблеми у відповіді користувача "Тома Хоутіна - таклін" вище:
synchronized (lock) {
makeWakeupNeeded();
lock.notifyAll();
}
Якраз той факт, що "замок" передається як аргумент синхронізовано () і він також використовується в "lock" .notifyAll ();
Після того, як я зробив це в цих двох місцях, я працював
Я отримав IllegalMonitorStateException
час, намагаючись прокинути нитку в / з іншої class
/ нитки. У java 8
ви можете використовувати lock
функції нового паралелізму API замість з synchronized
функцій.
Я вже asynchronous
зберігав об’єкти для трансакцій websocket в WeakHashMap
. Рішення в моєму випадку було також зберегти lock
об'єкт вConcurrentHashMap
протягом synchronous
відповідей. Приміткаcondition.await
(НЕ .wait
).
Для обробки декількох ниток я використовував a Executors.newCachedThreadPool()
для створення пулу ниток .
Ті, хто використовує версію Java 7.0 або нижче, можуть направити код, який я тут використав, і він працює.
public class WaitTest {
private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
public void waitHere(long waitTime) {
System.out.println("wait started...");
lock.lock();
try {
condition.await(waitTime, TimeUnit.SECONDS);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
lock.unlock();
System.out.println("wait ends here...");
}
public static void main(String[] args) {
//Your Code
new WaitTest().waitHere(10);
//Your Code
}
}