2015-04-21 10 views
6

devo tale scenario (questo è Java pseudo codice):Come sincronizzare la consegna dell'array tra 2 thread di piscina?

C'è un filo principale che:

1) crea un'istanza di una matrice di tipo C:

C[] arr = new C[LARGE]; 

2) crea e presenta compiti che popolano (effettuando le operazioni di CPU bound) l'arr a un pool P1:

for (int i = 0; i < populateThreadCount; i++) { 
    p1.submit(new PopulateTask(arr, start, end)) 
} 

Ogni task popola diversa gamma di: Indice s in arr so a questo punto la sincronizzazione non è necessaria tra i thread nel pool P1.

3) il thread principale attende fino a quando non vengono completate tutte le attività di popolamento.

4) una volta che l'arr è popolato, thread principale crea e sostiene compiti di caricamento (IO operazioni rilegate) il contenuto di arr, ad un pool P2:

for (int i = 0; i < uploadThreadCount; i++) { 
    p2.submit(new UploadTask(arr, start, end); 
} 

Come precedentemente, gli intervalli non si sovrappongono ogni thread ha il proprio intervallo, quindi non è necessaria alcuna sincronizzazione interna tra thread nel pool P2.

Nelle attività di caricamento e caricamento gli intervalli sono diversi in quanto vi è un numero diverso di thread per gestire ciascun tipo.

Ora sto pensando a quale sia il modo più efficiente per sincronizzarlo.

L'utilizzo di CopyOnWriteArrayList non è un'opzione in quanto può essere molto grande (milioni di elementi).

La mia idea iniziale era di sincronizzare brevemente un compito popolano dopo la creazione di un'istanza di una classe C e poi lo stesso in un compito di upload:

C[] arr = new C[LARGE]; 

for (int i = 0; i < populateThreadCount; i++) { 
p1.submit(new PopulateTask(arr, start, end) { 

    void run() { 
    for (int j = start; j <= end; j++) { 
    ... do some heavy computation ... 
    arr[j] = new C(some_computed_data); 
    synchronized(arr[j]) {} 
    } 
    } 

}); 
} 

for (int i = 0; i < uploadThreadCount; i++) { 
p2.submit(new UploadTask(arr, start, end) { 

    void run() { 
    for (int j = start; j <= end; j++) { 
    synchronized(arr[j]) { 
    upload(arr[j]); 
    } 
    } 
    } 

}); 
} 

ma non so se questo è corretto, soprattutto se questo blocco sincronizzato vuoto non verrà ottimizzato da javac o JIT. Non riesco a creare le istanze della classe C prima di avviare le attività di popolamento, poiché per questo ho bisogno dei dati calcolati.

Qualche idea, se è corretta e se non un modo per farlo meglio?

+0

Non capisco cosa si sta cercando di sincronizzare, e perché. –

+0

@JBNizet: (S) sta cercando di assicurarsi che le istanze di 'UploadTask' non provino a caricare gli elementi di array che le istanze di' PopulateTask' non hanno ancora terminato di compilare. – ruakh

+0

"3) il thread principale attende fino a quando non vengono completate tutte le attività popolate." Se questo è il caso, allora non vedo cosa c'è da sincronizzare. – Arkadiy

risposta

2

Non è necessario sincronizzare nulla. L'esecutore offre le garanzie di visibilità della memoria di cui hai bisogno. In particolare, vedere le concurrent package documentation: azioni

  • in un filo prima della presentazione di un Runnable all'esecutore accadere, prima che inizi la sua esecuzione. Allo stesso modo per Callables inviato ad un ExecutorService.
  • Azioni eseguite dal calcolo asincrono rappresentate da un'azione Future prima-prima successiva al recupero del risultato tramite Future.get() in un altro thread.

Quindi, le modifiche apportate dai compiti presentati al primo esecutore accadere prima cosa il filo principale faccia dopo l'esecutore ha finito di (seconda regola) eseguire, e quale il filo principale fa con la matrice avviene prima delle azioni eseguite dalle attività inviate al secondo esecutore (prima regola).

Poiché accade prima che sia transitiva, le attività inviate al secondo esecutore vedranno le modifiche apportate dalle attività inviate al primo.

+0

Ha senso. L'ho saltato dallo pseudo codice sopra ma questo è il modo in cui effettivamente aspetto che i compiti finiscano - Prendo tutti i Futures restituiti da submit, li metto nell'array e una volta che tutti sono stati inviati chiamo .get() su ciascuno di loro nel thread principale. – Janek

+0

Va bene, sebbene tu possa lasciare che l'esecutore faccia quello per te chiamando invokeAll(): http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ExecutorService.html#invokeAll% 28java.util.Collection% 29 –

Problemi correlati