2011-01-26 3 views
5

Brian Goetz's ha scritto un bell'articolo sul fork-join allo http://www.ibm.com/developerworks/java/library/j-jtp03048.html. In esso, elenca un algoritmo di tipo merge usando il meccanismo fork-join, in cui esegue l'ordinamento su due lati di un array in parallelo, quindi unisce il risultato.Visibilità della memoria nel fork-join

L'algoritmo ordina due sezioni diverse della stessa matrice contemporaneamente. Perché non è un AtomicIntegerArray o qualche altro meccanismo necessario per mantenere la visibilità? Che garanzia c'è che un thread vedrà le scritture fatte dall'altro, o si tratta di un bug insignificante? Come seguito, Scala ForkoinScheduler fa anche questa garanzia?

Grazie!

+0

Operano su diverse sezioni dell'array. Non c'è contesa fino alla fusione. –

+3

Sono d'accordo che stanno operando su diverse sezioni. Ma la semantica del modello di memoria di Java più o meno dice che non tutti i thread sono garantiti per vedere tutte le scritture (a meno che la variabile non sia volatile). Secondo questo blog: http://jeremymanson.blogspot.com/2009/06/volatile-arrays-in-java.html anche usando un volatile int [] non è sufficiente per garantire che altri thread vedano le tue scritture sull'array –

risposta

5

Il join (di ForkJoin) richiede di per sé un punto di sincronizzazione, che è l'informazione più importante. Un punto di sincronizzazione garantirà che tutte le scritture che si verificano siano visibili dopo tale punto.

Se dai un'occhiata al codice puoi vedere dove si trova il punto di sincronizzazione. Questo è solo un metodo di chiamata invokeAll

public static void invokeAll(ForkJoinTask<?> t1, ForkJoinTask<?> t2) { 
    t2.fork(); 
    t1.invoke(); 
    t2.join(); 
} 

Qui forchette t2 in un altro processo, t1 esegue il suo compito e che chiamare filo attenderà sul t2.join(). Quando si passa t2. Saranno quindi visibili tutte le scritture su t1 e t2.

Modifica: questa modifica è solo per dare un po 'più di una spiegazione di cosa intendevo per punto di sincronizzazione.

Diciamo che si dispone di due variabili

int x; 
volatile int y; 

Ogni volta che si scrive a y tutte le scritture che è accaduto prima di leggere y sarà disponibile. Ad esempio

public void doWork(){ 
    x = 10; 
    y = 5; 
} 

Se un altro thread legge y = 5 che thread è garantita leggere x = 10. Questo perché la scrittura di y crea un punto di sincronizzazione in cui tutte le scritture prima detto punto sarà visibile dopo la scrittura.

Con la forcella Join pool, il join di ForkJoinTask creerà un punto di sincronizzazione. Ora se t2.fork() e t1.invoke() l'unione di t2 si accerterà che tutte le scritture che sono successe in precedenza saranno viste. Dal momento che tutte le scritture precedenti sono all'interno della stessa struttura, sarà sicuro per la visibilità.

Sarei felice di spiegare ulteriormente se questo non è chiaro.

+0

È 'invokeAll' chiamato da' coInvoke'? –

+0

E, solo per completare la risposta, vedere anche http://java.sun.com/docs/books/jls/third_edition/html/memory.html#64058. –

+0

@Danciel C. Sobral, interessante che chiedi, mentre stavo scrivendo questo esempio stavo cercando il metodo coInvoke. Sembra che il metodo coInvoke stesso sia stato eliminato dal codice sorgente. Questo almeno non riesco a trovarlo più. –

1

Solo un'ipotesi: l'unione include l'adesione a una Discussione e l'unione garantisce la visibilità.

La seconda parte è sicura; Non so come viene implementata la fusione.