Обратите внимание (как указывали другие), что вы должны использовать один и тот же объект для блокировки/синхронизации в обоих потоках.
Если вы хотите, чтобы ваш основной поток продолжался сразу после вызова notify
, вы должны временно отказаться от блокировки. В противном случае wait
будет вызван только после того, как вторичная нить покинет блок synchronized
. И никогда не рекомендуется держать блокировку в длительном вычислении!
Один из способов, как добиться того, чтобы использовать wait(int)
на замке вместо sleep
, потому что wait
освобождает замок синхронизации временно:
public class Tester {
private static final Object lock = new Object();
public static void main(String[] args) {
Thread t = new Thread(new MyRunnable());
t.start();
synchronized (lock) {
try {
System.out.println("wating for t to complete");
lock.wait();
System.out.println("wait over");
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
static class MyRunnable implements Runnable {
public void run() {
System.out.println("entering run method");
synchronized (lock) {
System.out.println("entering syncronised block");
lock.notify();
try {
lock.wait(1000); // relinquish the lock temporarily
} catch (InterruptedException ex) {
System.out.println("got interrupted");
}
System.out.println("leaving syncronized block");
}
System.out.println("leaving run method");
}
}
}
Однако при использовании этих примитивов низкого уровня может быть очень подвержен ошибкам, и я 'd препятствовать их использованию. Вместо этого я предлагаю вам использовать для этого примитивы Java высокого уровня. Например, вы можете использовать CountDownLatch
, которая позволяет одной нити ждать до тех пор, пока рассчитывать другие потоки вплоть до нуля:
import java.util.concurrent.*;
public class TesterC {
private static final CountDownLatch latch = new CountDownLatch(1);
public static void main(String[] args) {
Thread t = new Thread(new MyRunnable());
t.start();
System.out.println("wating for t to complete");
try {
latch.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("wait over");
}
static class MyRunnable implements Runnable {
public void run() {
System.out.println("entering run method");
try {
latch.countDown();
Thread.sleep(1000);
} catch (InterruptedException ex) {
System.out.println("got interrupted");
}
System.out.println("leaving run method");
}
}
}
Здесь не нужно синхронизировать ничего, защелка делает все для вас. Есть много других примитивов, которые вы можете использовать - семафоры, обменник, потоки с безопасностью и т. Д. Проводник java.util.concurrent
.
Возможно, даже лучшим решением является использование API более высокого уровня, например, Akka. Там вы работаете с Actors или Software transactional memory, которые легко скомпилированы и избавят вас от большинства проблем параллелизма.
Вы не синхронизируете на тех же объектах – MadProgrammer
MyRunnable.this == r! = T –
@ raul8 Редактирование вопроса и вставка в ответ делает неправильный ответ неверным. Было бы лучше добавить еще один вопрос. –