2016-03-28 21 views
5

Ho letto ovunque che se un campo viene utilizzato contemporaneamente da thread diversi, è necessaria una sorta di sincronizzazione e, se viene utilizzato da un solo thread, non è necessario. Ma cosa succede se viene utilizzato da thread diversi, ma non allo stesso tempo? Diamo un codice come questo:È sicuro utilizzare un oggetto in thread diversi, ma NON allo stesso tempo?

Thing thing = new Thing(); 
Thread t1 = new Thread(new MyRunnable(thing)); 
Thread t2 = new Thread(new MyRunnable(thing)); 
t1.start(); 
t1.join();//Wait for t1 to finish 
t2.start(); 

MyRunnable è:

class MyRunnable implements Runnable { 
    //skipped constructor and field "private final Thing thing" 
    public void run() { 
     thing.someUpdate(); 
    } 
} 

E 'sicuro? Tutti gli aggiornamenti fatti da t1 sono visibili da t2?

risposta

9

In questo caso quindi i cambiamenti sono visibili perché Thread.join e Thread.start crea relazioni che accade-prima tra le azioni in entrambi i thread. Vedere Memory Consistency Errors:

  • Quando un'istruzione invoca Thread.start, ogni affermazione che ha un rapporto accade, prima che con questa affermazione ha anche un rapporto accade, prima di ogni istruzione eseguita dalla nuova filo . Gli effetti del codice che ha portato alla creazione del nuovo thread sono visibili per il nuovo thread.

  • Quando un thread termina e provoca un Thread.join in un altro thread ritorno, allora tutte le istruzioni eseguite dal thread terminato hanno un accade-prima relazione con tutte le dichiarazioni seguendo il successo join. Gli effetti del codice nel thread sono ora visibili nel thread che ha eseguito il join.

Se non si sta utilizzando questi metodi in questo ordine, quindi le modifiche non possono essere visibili. Non è necessario che i thread siano in esecuzione contemporaneamente per causare un problema perché i valori possono essere memorizzati nella cache all'interno di un thread o potrebbero verificarsi degli ottimamenti, ecc.

+1

Probabilmente dovresti citare le parti rilevanti della documentazione a cui ti sei collegato, solo in caso di link rot. –

0

Nel tuo caso è sicuro poiché entrambi i thread non funzionano contemporaneamente.

0

join() metodo è un metodo di blocco e attende il completamento di un thread. t2 dovrebbe vedere tutti gli aggiornamenti di t1.

0

È sicuro in questo caso. Le modifiche apportate da t1 sull'oggetto thing saranno visibili a t2. Se non ci fosse t1.join(); il codice non sarebbe stato thread-safe.

t1.start(); 
t1.join();//Wait for t1 to finish 
t2.start(); 
1

Penso che la domanda sia troppo astratta. Risposta generale alla domanda "Tutti gli aggiornamenti fatti da t1 sono visibili da t2?" è sì". Ma saranno visibili solo a causa del modo in cui esegui i thread. I thread nel tuo esempio non sono paralleli. Quindi, sì, in questo esempio, i campi di MyRunnable saranno visibili per entrambi i thread. Ma la classe MyRunnable non è thread-safe. Se verrà utilizzato con thread simultanei, probabilmente avrai problemi con lo . Dipende dai dettagli di MyRunnable.someUpdate(). È necessario utilizzare la parola chiave "volatile" per i campi, le classi "java.util.concurrent. *" O qualsiasi meccanismo di sincronizzazione, se necessario. Forse questa documentazione sia utile per iniziare: https://docs.oracle.com/javase/tutorial/essential/concurrency/atomic.html

+0

someUpdate() scrive nei campi dell'oggetto Thing, che sono solo campi privati ​​(non volatili, nessuna sincronizzazione). – ElectronWill

+0

Quindi ci sono alcuni modi: 1. contrassegnare questi campi come volatili (come è scritto nella documentazione precedente minimizza i rischi, ma i problemi sono ancora possibili) 2. rendere "vuoto someUpdate() sincronizzato". sarai al sicuro al 100% ma il tuo codice sarà lento perché significa che solo un thread al momento eseguirà questo metodo. 3. sincronizzare parti speciali all'interno di someUpdate() che sono sezioni critiche. In realtà è difficile dire cosa fare se l'attività è così astratta. Dipende davvero da cosa vuoi ottenere con il tuo codice. –

+1

Io sceglierò un buon metodo (probabilmente renderò un aggiornamentoUpdate, perché non voglio che venga chiamato da più thread contemporaneamente) Grazie! – ElectronWill