Nota (come altri hanno sottolineato anche) che è necessario utilizzare lo stesso oggetto per il blocco/sincronizzazione in entrambi i thread.
Se si desidera che il thread principale continui immediatamente dopo che è stato chiamato notify
, è necessario rinunciare temporaneamente al blocco. Altrimenti, wait
verrà chiamato solo dopo che il thread secondario lascia il blocco synchronized
. E non è mai una buona idea tenere un lucchetto in un calcolo a lungo termine!
Un modo come raggiungere è quello di utilizzare wait(int)
sulla serratura invece di sleep
, perché wait
rilascia il blocco di sincronizzazione temporanea:
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");
}
}
}
Tuttavia, utilizzando queste primitive di basso livello può essere molto soggetto ad errori e ho sconsigliarne l'uso. Invece, ti suggerirei di usare i primitivi di alto livello di Java per questo. Ad esempio, è possibile utilizzare CountDownLatch
che permette un'attesa thread fino a quando altri thread contano fino a zero:
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");
}
}
}
Qui non c'è bisogno di sincronizzare qualsiasi cosa, il fermo fa tutto per te. Esistono molti altri primitivi che puoi usare: semafori, uno scambiatore, code thread-safe, ecc. Esplora il pacchetto java.util.concurrent
.
Forse la soluzione migliore è utilizzare anche API di livello superiore, come ad esempio Akka. Qui si lavora con Actors o Software transactional memory, che può essere composto facilmente e risparmiato dalla maggior parte dei problemi di concorrenza.
fonte
2013-07-01 08:09:39
Non si sta eseguendo la sincronizzazione sugli stessi oggetti – MadProgrammer
MyRunnable.this == r! = T –
@ raul8 La modifica della domanda e l'inserimento nella risposta rendono la risposta corretta non valida. Sarebbe meglio aggiungere un'altra domanda. –