iBaffiPro ha scritto:
perché l'obiettivo è tenere assolutamente questo pezzo invariato:
if(matrix.get(j).get(i).longValue() <= limit){
numbers.add(matrix.get(j).get(i));
matrix.get(j).set(i,null);
}
E questo "assolutamente" in che senso? PERCHÉ??
iBaffiPro ha scritto:
Il problema è numbers, non matrix. matrix viene editata correttamente.
Allora, ho guardato un attimo bene e .... direi che ho capito. Ma la questione è MOLTO più ampia e devo descrivertela meglio.
Il concetto del Fork/Join può essere utilizzato per velocizzare svariati tipi di operazioni: ad esempio per ordinare una lista, per fare ricerche, per effettuare una "riduzione" (da
N valori ad un solo valore, es. il concetto di sum(lista) ), ecc...
Se prendiamo proprio il sum(), si ha una cosa tipo (esempio):
6 8 4 10 6 16 9 2 12
\ / \ / \ /
\ / \ / \ /
Thread1 Thread2 Thread3
calcola 18 calcola 32 calcola 23
\ / |
\ / |
\ / |
"join" 18+32 |
=50 /
\ /
\ /
\ /
"join" 50+23
=73
Se ben ricordi, nel metodo compute() del task del Fork/Join pool si fa in generale una cosa di questo tipo:
protected XYZ compute() {
if (se_il_task_è_piccolo) {
// computa sequenzialmente
return // il risultato di questa computazione
} else {
// crea leftTask
leftTask.fork();
// crea rightTask
XYZ risultatoRight = rightTask.compute();
XYZ risultatoLeft = leftTask.join();
return // qui COMBINA risultatoLeft e risultatoRight
}
Questo chiaramente se il F/J si usasse per applicare il concetto di "riduzione", che poi in pratica è quella fase finale del metodo in cui, come vedi, COMBINA il risultato dei due sotto task left e right.
Nel ForkJoinListMutator che avevo scritto io e che ti avevo ampiamente mostrato, l'obiettivo NON era quello di fare una "riduzione", ma solo di spezzare una "grossa" lista in tanti pezzi e fare in modo che la MUTAZIONE degli elementi della lista fosse ben parallelizzabile, appunto con il F/J pool. Quindi lì nel mio codice NON c'è una fase finale in cui "combina" due risultati.
Quindi, FINTANTO che la implementazione del ElementMutator<T> va a toccare SOLO l'elemento i-esimo della lista, questo non causa alcun problema ed è tutto corretto. Questo era (è) l'obiettivo del mio ForkJoinListMutator.
Ora, il TUO caso. Tu con il "mio" ForkJoinListMutator non stai solo usando/modificando l'elemento i-esimo ma .... stai anche MUTANDO un oggetto "condiviso", quel
SynchronizedObjects.
Nel SynchronizedObjects hai messo sì la sincronizzazione, con il ReentrantReadWriteLock, quindi la classe di per sé è thread-safe, cioè i metodi sono "atomici" e causano mutua-esclusione tra thread. (non ho verificato tutto per bene ma a vista pare ok). Se un thread A chiama so.setNumbers(...) in quel frangente nessun altro thread può fare operazioni su quello stesso oggetto
so. Quindi NON è questo il problema.
Il problema è più fine: nel parallelFor fai un so.getNumbers() quasi all'inizio e poi un so.setNumbers(numbers) alla fine (li hai commentati ma volevi farli! ).
Quale è il problema? Il problema è che parallelFor è usato da thread differenti. Un elemento i-esimo è trattato da un SOLO thread ma tu non sai COME saranno intercalate le operazioni di parallelFor tra i thread. Potrebbero fare:
Thread1 Thread2
so.getNumbers()
so.getNumbers()
..........
so.setNumbers()
so.setNumbers()
oppure
Thread1 Thread2
so.getNumbers()
so.getNumbers()
..........
so.setNumbers()
so.setNumbers()
oppure ecc.....
Quindi che cosa setti??? NON LO SAI! Dipende dalle tempistiche più o meno (s)fortunate dei thread. E il problema è proprio quello: la mutazione di un oggetto condiviso che viene usato nel contesto di tutti i thread del F/J pool.
E sai perché stai facendo tutti questi casini?
Perché non hai le idee chiare sul multi-threading/concorrenza. E in generale non hai sufficienti basi su Java. Oltretutto stai facendo anche stupidaggini tipo:
public void setNumbers(List<Long> numbers) {
reentrantReadWriteLock.writeLock().lock();
try {
this.numbers = numbers;
} catch (Exception e){
this.numbers = null;
} finally {
reentrantReadWriteLock.writeLock().unlock();
}
}
Ti rendi conto che un assegnamento come
this.numbers = numbers; NON causa eccezioni quindi quel catch è totalmente inutile?
Lo so, te lo sto già dicendo da tempo e mi spiace ripeterlo. Ma secondo me queste tue esercitazioni sono abbastanza, molto inutili, ti stanno portando via davvero un sacco di tempo .... tempo che invece potresti dedicare (meglio) a leggere un bel libro su Java ....
Insomma ... stai proprio solo "giocherellando" con Java ....
P.S. Guarda, io in queste settimane ho ripreso a studiare Kotlin (un altro linguaggio per la JVM), che purtroppo non lo uso per lavoro quindi ogni tanto devo sempre riprendere quasi dall'inizio. Sabato, l'altro ieri, mi sono messo a giocherellare un po' con http4k, un toolkit per fare webapp/web-service in Kotlin.
Sì ma io ho 2 certificazioni su Java e 13+ anni di esperienza, quindi se permetti, credo che
posso "giocherellare" con queste cose ....