Thread Safe

di il
3 risposte

Thread Safe

SafeSet deve essere Thread Safe, l'ho fatto in questa maniera, ma sarebbe stato possibile usare delle collezioni sincronizzate evitando synchronized sui metodi? In realtà così andrebbe bene? perchè tipo non mi trovo certe volte con il primo add che restituisce "false".

Spiegazione:
Il metodo remove rimuove un elemento dall'insieme, ma la rimozione è definitiva solo dopo una seconda chiamata. Il metodo contains verifica se l'insieme contiene un dato elemento(in basea equals).

import java.util.*;


public class SafeSet<T>{
    Set<T> trash = new HashSet<>();
    Set<T>  present= new HashSet<>();

    public SafeSet(){    }

    public synchronized boolean add(T x){
            return present.add(x);
    }
    public synchronized boolean remove(T x){
        if(present.contains(x)) return present.remove(x) && trash.add(x);
        else if(trash.contains(x)) return trash.remove(x);
        else return false;
    }
    public synchronized boolean contains(T x){
        return present.contains(x);
    }

    public static void main(String[] args){
        SafeSet<String> a=new SafeSet();
        Thread t1=new Thread(){
            public void run(){
                System.out.println(a.add("ciao") +" add ciao di T1");
                System.out.println(a.add("mondo") +" add mondo di T1");
                System.out.println(a.remove("ciao") +" remove ciao di T1");
                System.out.println(a.contains("ciao") +" contains ciao di T1");
                System.out.println(a.remove("ciao")+" remove ciao di T1");
                System.out.println(a.contains("ciao")+" contains ciao di T1");
            }
        };
        Thread t2=new Thread(){
            public void run(){
                System.out.println(a.add("ciao") +" add ciao di T2");
                System.out.println(a.add("mondo") +" add mondo di T2");
                System.out.println(a.remove("ciao") +" remove ciao di T2");
                System.out.println(a.contains("ciao") +" contains ciao di T2");
                System.out.println(a.remove("ciao")+" remove ciao di T2");
                System.out.println(a.contains("ciao")+" contains ciao di T2");
            }
        };
        t1.start();
        t2.start();
    }
}

3 Risposte

  • Re: Thread Safe

    HalJordan ha scritto:


    SafeSet deve essere Thread Safe, l'ho fatto in questa maniera
    Sì, corretto. Avendo messo synchronized sui 3 metodi "di istanza", gli oggetti SafeSet sono di fatto thread-safe.

    HalJordan ha scritto:


    ma sarebbe stato possibile usare delle collezioni sincronizzate evitando synchronized sui metodi?
    Se intendi il fatto di mettere al posto dei due new HashSet<>() un tipo di collezione "set" già di per sé thread-safe (e togliendo i synchronized), la risposta è: no.
    Ma non perché una collezione thread-safe non sarebbe appropriata. Per un altro motivo: nel tuo remove fai delle operazioni composte "se x, fai y" e questo insieme di operazioni DEVE essere "atomico".
    Avendo in trash/present delle collezioni thread-safe, le singole operazioni contains/remove/add sulle collezioni sarebbero atomiche. Ma il tuo insieme di operazioni nel TUO remove no.

    HalJordan ha scritto:


    perchè tipo non mi trovo certe volte con il primo add che restituisce "false".
    Ciascuno dei due thread fa lo stesso identico a.add("ciao") (quindi il valore è lo stesso). Da un thread il add darà true (=inserito) e nell'altro thread darà false (=non inserito perché già presente).
    Quale dei due thread riesce a fare PRIMA il add rispetto all'altro non è garantito, dipende dal caso ..
  • Re: Thread Safe

    Grazie andbin sei stato chiarissimo su tutto, ultima cosa se dovessi migliorare una struttura del genere sempre seguendo gli obiettivi prefissi, è possibile fare un SafeSet implementando in questo caso proprio la struttura Set ed evitando le collezioni present,trash? o già come ho scritto può essere una valida implementazione?
  • Re: Thread Safe

    HalJordan ha scritto:


    è possibile fare un SafeSet implementando in questo caso proprio la struttura Set
    Se intendi il fatto di implementare la interfaccia Set, ovvero

    public class SafeSet<T> implements Set<T>

    Sì, tecnicamente sarebbe perfettamente possibile farlo. Ovvio, non sarebbe banale. Implementare la interfaccia Set vuol dire molte cose, Set ha svariati metodi e concetti che dovresti rispettare (vedi javadoc ufficiale). Ma un conto è se dovessi implementare la logica del set da quasi-zero, un altro conto è se devi semplicemente fare da "passacarte" e delegare ad un set interno al tuo SafeSet.

    HalJordan ha scritto:


    ed evitando le collezioni present,trash?
    Il fatto dei due set trash/present è stata una tua scelta implementativa. Cioè il fatto che se rimuovi un oggetto, va prima a finire nel trash e poi se lo rimuovi di nuovo lo togli anche dal trash.
    E' una logica sensata ma non ha nulla a che fare direttamente con un "set".

    HalJordan ha scritto:


    già come ho scritto può essere una valida implementazione?
    Come l'hai scritto all'inizio, con i 3 metodi synchronized, è tecnicamente corretto.
    Solo per "pulizia" del codice sarebbe stato meglio tenere da parte il SafeSet e da un'altra parte il main e quant'altro.
Devi accedere o registrarti per scrivere nel forum
3 risposte