2016-05-26 13 views
5

Il modello di memoria Java fornisce garanzie di verifica prima per le interazioni del pool di thread? In particolare, le scritture effettuate da un thread di thread pool thread prima della fine dell'esecuzione di un elemento da una coda di lavoro saranno visibili a un thread di lavoro che esegue successivamente l'elemento successivo dalla coda?Il modello di memoria Java si verifica prima delle interazioni del pool di thread

La specifica (che personalmente trovo questa FAQ utile: http://www.cs.umd.edu/~pugh/java/memoryModel/jsr-133-faq.html#synchronization) stabilisce che "Una chiamata a start() su un filo avviene prima di qualsiasi azione nel thread iniziato.", O in poche parole, la memoria scrive fate prima di iniziare un thread verrà eseguito prima e visibile al metodo run() che il thread avviato sta per eseguire. È diverso per un pool di thread, l'avvio() normalmente viene eseguito prima di eseguire una scrittura. Si consideri un semplice flusso di lavoro in cui un oggetto contesto è mutato e passa all'azione successiva:

import java.util.concurrent.ExecutorService; 
import java.util.concurrent.Executors; 

public class Main { 

    private static class Container<T> { 
     private T value; 
     public T get() { 
      return value; 
     } 
     public void set(T newValue) { 
      value = newValue; 
     } 
    } 

    public static void main(String[] args) { 
     final Container<Integer> sharedObject = new Container<>(); 
     final ExecutorService executor = Executors.newFixedThreadPool(10); 
     // SKIPPED: pre-warm the executor so all worker threads are start()'ed 
     final Runnable read =() -> System.out.println("Got " + sharedObject.get()); 
     Runnable write =() -> { 
      sharedObject.set(35); 
      executor.execute(read); 
     }; 
     executor.execute(write); 
     // SKIPPED: wait until done 
    } 
} 

È la scrittura per sharedObject.value da write.run() garantito per essere visibile (non chiedere su ordinazione, questo è ovvio) per read.run()?

(PS: ho capito che, per rendere valuevolatile non fornire questa garanzia)

Update (complementare alla risposta): pacchetto di documentazione di riepilogo per java.util.concurrent riassume garanzie di coerenza di memoria forniti dal linguaggio ed estesi dal quadro : https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/package-summary.html#MemoryVisibility

risposta

4

Penso che sia garantito essere visibile.ExecutorService estende Executor, e la javadocs per Executor dire: effetti consistenza

memoria: le azioni in un filo prima di inviare un oggetto a un RunnableExecutoraccadere, prima sua esecuzione inizia, forse in un altro thread.

Con la mia lettura, corrisponde a quello che sta succedendo nel tuo esempio. Il write runnable sottopone la read eseguibile, per cui v'è un accade-prima relazione tra eventi prima della presentazione del filo write (cioè il set chiamata) e gli eventi successiva nel read filo (cioè il get chiamata).

Il fatto che il write eseguibile è esso stesso una presentata significa che c'è anche un accade-prima tra la creazione dell'oggetto Container e la chiamata a set.

2

Citando javadoc di ExecutorService:

effetti consistenza di memoria: le azioni in un filo prima della presentazione di un compito o di RunnableCallable ad un ExecutorServiceaccadere, prima eventuali azioni intraprese da questo compito, che a sua volta accadere, prima il risultato viene recuperato tramite Future.get().

Tuttavia, non dice nulla su due attività aggiunte alla coda e sull'elaborazione dell'attività 1, prima dell'elaborazione dell'attività 2, vista dall'attività. Solo che l'aggiunta dell'attività alla coda avviene prima dell'attività che l'elabora e l'esecuzione dell'attività avviene prima che il risultato venga recuperato dall'invocatore originale.

Aggiorna

Non c'è accade-prima correlazione tra due diversi compiti, scritte in modo indipendente, anche se in qualche modo uno è conosciuto la corsa fino al completamento prima inizia l'altro in esecuzione.

Naturalmente, quando un compito sottopone l'altro, come si fa in questione, qualsiasi azione intrapresa nel compito 1 prima sottopone compito 2, sarà accadrà-prima della esecuzione di un task 2.

Se l'attività 1 continua a svolgere altre attività dopo aver inviato l'attività 2, ovviamente non vi è alcuna garanzia, perché l'attività 2 può essere eseguita e completata prima che l'attività 1 possa continuare a funzionare.

+2

Io non ti seguo - la tua conclusione è opposta alla citazione che hai usato ... Nell'esempio dell'opzione, c'è sicuramente una relazione hb tra 'sharedObject.set (35)' e 'println'. Forse hai perso il fatto che la seconda attività viene aggiunta alla coda * dalla prima attività *, non nel thread principale. – assylias

+0

@assylias Hai ragione, mi è sfuggito questo fatto. Come suggerirebbe la formulazione della mia risposta, sto parlando di due compiti aggiunti in modo indipendente, non di un compito che ne presenta un altro. – Andreas

+0

Grazie per aver notato una discrepanza tra la mia domanda e l'esempio. L'esempio è ciò che volevo sapere ma non riuscivo a capire la domanda, sarebbe stato: sono le azioni di scrittura in 'write' create prima di sottoporre' read' visibile al thread 'read'. – Pavel

Problemi correlati