Scelta Thread

di il
6 risposte

Scelta Thread

Due istanze di MyThread condividono un array di interi, dopo aver avviato i due Thread l'array deve risultare inalterato.
public class myThread extends Thread{
    public int[] a;
    public myThread(int[] a){
        this.a=a;
    }
    public void run(){
        final int n=a.length-1;
        //1
            for (int i = 0; i <= n / 2; i++) {
                //2
                int temp = a[i];
                a[i] = a[n - i];
                a[n - i] = temp;
                //3
            }
        //4
    }
}
devo scegliere tra le seguenti opzioni per rendere il programma esente da race condition(possibile indicare più opzioni):

(a) non c'è bisogno di aggiungere nulla
(b) aggiungere il modificatore synchronized al metodo run
(c) 1="synchronized(this){" 4="}"
(d) 1="synchronized{" 4="}"
(e) 1="synchronized(a){" 4="}"
(f) 1="synchronized(myThread.class){" 4="}"
(g) 1="a.wait()" 4="a.notify()"
(h) 2="synchronized(this){" 3="}"
(i) 2="synchronized(a){" 3="}"
(j) 2="synchronized(a){" 3="}"
(k) 2="synchronized(myThread.class){" 3="}"



a - sbagliata per ovvie ragioni, l'array potrebbe non restare inalterato anzi.
b - scelta giusta
c - non mi interessa avere il mutex di un oggetto thread, sbagliato.
d - synchronized così scritto è sbagliato, deve avere almeno un oggetto come parametro
e, f - non lo so, a me sembrano giuste
g - errata, perchè poi dovrei catturare anche l'eccezione e quindi non basta scrivere solo a.wait
h-i-j-k sono tutte sbagliate no? il contatore i dei due Thread potrebbero comunque risultare completamente diversi nel momento dello scambio


Ho ragionato bene secondo voi? Grazie mille a tutti a prescindere.

6 Risposte

  • Re: Scelta Thread

    HalJordan ha scritto:


    b - scelta giusta
    c - non mi interessa avere il mutex di un oggetto thread, sbagliato.
    d - synchronized così scritto è sbagliato, deve avere almeno un oggetto come parametro
    e, f - non lo so, a me sembrano giuste
    g - errata, perchè poi dovrei catturare anche l'eccezione e quindi non basta scrivere solo a.wait
    h-i-j-k sono tutte sbagliate no? il contatore i dei due Thread potrebbero comunque risultare completamente diversi nel momento dello scambio
    No, la b è sbagliata. Hai DUE istanze di myThread, quindi il synchronized sul run() secondo te cosa fa?

    synchronized(this) (la c) è equivalente al synchronized sul run(), quindi anch'essa sbagliata.

    Quello che serve è un oggetto di lock che sia veramente "condiviso". E quindi può essere l'array stesso oppure qualcosa di ancora più "globale" come il myThread.class che sarebbe ovviamente più esagerato ma comunque tecnicamente corretto.

    E quindi puoi mettere un blocco synchronized tra //1 e //4 oppure tra //2 e //3. Perché quello che conta è che quello scambio sia "atomico" e che ci sia la "mutua-esclusione" tra i due thread.

    Se metti il synchronized tra //1 e //4 l'intero insieme di scambi è "atomico". Se lo metti tra //2 e //3 (cioè nel corpo del for) solo ciascun singolo scambio è atomico. Ma è sufficiente.
  • Re: Scelta Thread

    Grazie andbin sempre affidabilissimo e paziente.
    (b) se metto synchronized sul metodo run(), tale metodo verrà usato solo da un Thread alla volta, e quindi il primo Thread inverte l'array e il secondo lo riporta alla normalità no?

    (c) con synchronized(this) un Thread ha il lock sulla sua istanza e quindi non bloccherebbe comunque il processo dell'altro Thread sull'array?

    ma con myThread.class faccio in modo che il primo Thread ha il lock sulla classe stessa e quindi blocca il secondo Thread?

    ti ringrazio ancora.
  • Re: Scelta Thread

    HalJordan ha scritto:


    (b) se metto synchronized sul metodo run(), tale metodo verrà usato solo da un Thread alla volta, e quindi il primo Thread inverte l'array e il secondo lo riporta alla normalità no?
    No. Il synchronized sul run() fa acquisire il lock sulla istanza di myThread. Ma tu hai DUE istanze. Quindi ciascun thread usa un "suo" lock. Due oggetti di lock differenti = nessuna mutua-esclusione!

    HalJordan ha scritto:


    (c) con synchronized(this) un Thread ha il lock sulla sua istanza e quindi non bloccherebbe comunque il processo dell'altro Thread sull'array?
    Sì ma è uguale al b) !

    Fare un:

    public synchronized void unMetodo() { ...corpo... }

    è perfettamente uguale, a livello funzionale, a fare:
    public void unMetodo() {
        synchronized (this) { ...corpo... }
    }
    Non c'è differenza a livello di funzionamento.

    HalJordan ha scritto:


    ma con myThread.class faccio in modo che il primo Thread ha il lock sulla classe stessa e quindi blocca il secondo Thread?
    myThread.class è il riferimento alla istanza di java.lang.Class associata alla classe myThread. Ogni tipo reference, a runtime ha associata una istanza di Class, che quindi è "globale". E quindi anche se è più "esagerato" come lock, funziona bene lo stesso.

    Ricorda: per vedere se c'è mutua-esclusione devi stabilire se due thread cercano di ottenere il lock sullo STESSO oggetto.
  • Re: Scelta Thread

    andbin ha scritto:


    No. Il synchronized sul run() fa acquisire il lock sulla istanza di myThread. Ma tu hai DUE istanze. Quindi ciascun thread usa un "suo" lock. Due oggetti di lock differenti = nessuna mutua-esclusione!
    Ah diavolo giusto, è la stessa cosa, non avevo capito bene synchronized su di un metodo.

    Se dovessi invece avere una sola istanza di myThread e usarla in due istanze di Thread, varrebbe lo stesso?

    andbin ha scritto:


    myThread.class è il riferimento alla istanza di java.lang.Class associata alla classe myThread. Ogni tipo reference, a runtime ha associata una istanza di Class, che quindi è "globale". E quindi anche se è più "esagerato" come lock, funziona bene lo stesso.

    Ricorda: per vedere se c'è mutua-esclusione devi stabilire se due thread cercano di ottenere il lock sullo STESSO oggetto.
    Quindi .class in questo genere di esercizio è corretto, ma in futuro con altro tipo di implementazione non va usato, perchè è brutto da vedere o c'è un motivo preciso?
    Per vedere se ho capito bene, se avessi due Thread che condividono due array(a e b) in cui il metodo run sposta i positivi di a in b:
    public void run(){
                for (int i = 0; i < a.length; i++) {
                    if (a[i] > 0) {
                        b[i] = a[i];
                        a[i] = 0;
                    }
                }
        }
    potrei mettere synchronized(a) prima di for o synchronized(b) dopo il for per una corretta compilazione.
    sbaglio invece nel caso in cui non aggiungo nulla o uso synchronized(this)
  • Re: Scelta Thread

    HalJordan ha scritto:


    Ah diavolo giusto, è la stessa cosa, non avevo capito bene synchronized su di un metodo.
    Il synchronized nella dichiarazione del metodo:
    * Su un metodo "di istanza" (non static), acquisisce il lock sulla istanza su cui è invocato.
    * Su un metodo "di classe" (static) acquisisce il lock sul Class relativo alla classe.

    HalJordan ha scritto:


    Se dovessi invece avere una sola istanza di myThread e usarla in due istanze di Thread, varrebbe lo stesso?
    La tua classe è extends Thread quindi quello che dici non ha granché senso.

    Ma se tu avessi scritto una classe implements Runnable e poi crei UNA (una sola!) istanza e la passi a DUE istanze di Thread, allora sì, un synchronized sul run() FA la mutua-esclusione, perché il lock è uno solo.

    HalJordan ha scritto:


    Quindi .class in questo genere di esercizio è corretto, ma in futuro con altro tipo di implementazione non va usato, perchè è brutto da vedere o c'è un motivo preciso?
    E' un po' raro dover usare Xyz.class come oggetto di lock esplicito in un blocco synchronized.

    HalJordan ha scritto:


    Per vedere se ho capito bene, se avessi due Thread che condividono due array(a e b) in cui il metodo run sposta i positivi di a in b:
    public void run(){
                for (int i = 0; i < a.length; i++) {
                    if (a[i] > 0) {
                        b[i] = a[i];
                        a[i] = 0;
                    }
                }
        }
    Sostanzialmente, stessa cosa di prima: tutto quel if e il suo corpo DEVE essere fatto in modo "atomico" dando mutua-esclusione tra i thread.

    Se metti il synchronized che racchiude tutto il for, succede che UN solo thread farà tutti gli spostamenti e l'altro non farà più nulla.
    Se metti il synchronized che racchiude solo il if, succede che a seconda delle tempistiche un thread farà alcuni spostamenti e l'altro thread ne farà alcuni altri.
  • Re: Scelta Thread

    Andbin non so cosa dirti se non grazie, mi auguro di poter ricambiare un giorno. Sei sempre gentilissimo e paziente. Grazie tante. Come al solito ho proprio difficoltà nella parte dei multiprocessi, magari a causa del mio scarso impegno ad aver eseguito esami del tipo Sistemi Operativi.
Devi accedere o registrarti per scrivere nel forum
6 risposte