Java >> Java tutorial >  >> Tag >> synchronized

Hvad er formålet med at overføre parameter til synkroniseret blok?

Fordi det er ligegyldigt, om jeg sender String's instans, fungerer Some random class's instans til den synkroniserede blok som den synkroniserede blok perfekt, uanset om parameteren sendes til blokken.

Formålet med parameteren er todelt:

  1. Det gør det muligt at synkronisere andet blokke på det samme objekt, så hvis du har to kodeblokke, der kan ændre tilstanden for det samme objekt, forstyrrer de ikke hinanden.

    For eksempel:

    public void getSum() {
        int sum = 0;
        synchronized (this.list) {
            for (Thingy t : this.list) {
                sum += t.getValue();
            }
        }
        return sum;
    }
    
    public void addValue(int value) {
        synchronized (this.list) {
            this.list.add(new Thingy(value));
        }
    }
    

    Der er det vigtigt, at vi synkroniserer begge dele adgang til list på tværs af tråde. Vi kan ikke have noget, der kalder addValue og tramper på listen, mens en anden tråd kalder getSum .

  2. Det gør det muligt at sikre, at du synkroniserer med den korrekte granularitet. Hvis du serialiserer adgang til en instansspecifik ressource, så giver det ikke mening at gøre det på tværs af instanser; Du bør tillade flere tråde i blokken, forudsat at de fungerer på forskellige instanser. Det er derfor, du ville synkronisere på this (eller mere normalt et felt med this ) for en instansspecifik ressource eller klassen (eller mere normalt et klassefelt), hvis det var en statisk ressource. På samme måde er der ingen grund til at synkronisere på this hvis du kun skal beskytte et bestemt felt af det.

    For eksempel:

    // (In MyClass)
    
    public void getThingySum() {
        int sum = 0;
        synchronized (this.thingyList) {
            for (Thingy t : this.thingyList) {
                sum += t.getValue();
            }
        }
        return sum;
    }
    
    public void addThingy(Thingy t) {
        synchronized (this.thingyList) {
            this.thingyList.add(t);
        }
    }
    
    public void getNiftySum() {
        int sum = 0;
        synchronized (this.niftyList) {
            for (Nifty n : this.niftyList) {
                sum += n.getValue();
            }
        }
        return sum;
    }
    
    public void addNifty(Nifty n) {
        synchronized (this.niftyList) {
            this.niftyList.add(t);
        }
    }
    

    Der synkroniserer vi adgang til this.thingyListthis.thingyList , ikke this eller MyClass.class . Det er fint, hvis en tråd kalder getThingySum mens en anden tråd kalder addNifty , så synkronisering på this ville være overkill.

Re din str eksempel:

public  void makeWithdrawal(int amount){
    String str="asd"
    synchronized (str /* pass any non-null object the synchronized block works*/) {
        if(account.getAmount()>10){

            try{
                Thread.sleep(5000);             
            }catch(InterruptedException e){
                e.printStackTrace();
            }
            account.withdraw(amount);
            System.out.println(Thread.currentThread().getName()+" has withdrawn 10, current balance "+ account.getAmount());
        }else{
            System.out.println("Insufficient funds "+account.getAmount());
        }
    }

}

Kommentaren der er forkert, enhver ikke-null forekomst vil ikke beskytte denne kode tilstrækkeligt. Grunden til, at ovenstående ser ud til at virke, er strenginternering :Den samme String instans bruges af alle tråde, fordi strengliteraler automatisk indsættes i strengen intern pool. (Hvilket betyder, at du oversynkroniserer; det er JVM-dækkende, ikke instansspecifikt.) Så det virker, men ikke fordi det er et hvilket som helst objekt. Hvis du ændrede det fra:

String str = "asd";

til

Object o = new Object();

og synkroniseret på det, ville det ikke gøre noget for at serialisere adgangen til kontoen.

I dit eksempel er den rigtige ting at synkronisere på this.account .


hvis alligevel synkroniseret blok stopper to tråde fra at komme ind i den kritiske sektion samtidigt. Hvorfor er der så behov for at føre et argument?

Synkroniseret blok bestemmer, hvilke tråde der skal stoppes baseret på det objekt, du sender til det. Objektet, du passerer, tjener som identifikator for monitorsektionen, der er beskyttet af den synkroniserede blok.

Du kan have mange skærmsektioner i dit program, som alle kan udføres samtidigt med hinanden. For eksempel, hvis du har to ikke-relaterede samlinger, der skal tilgås samtidigt, kan du opsætte separate skærmsektioner for hver samling. På denne måde vil tråde kun blive stoppet, når andre tråde allerede har adgang til den samme samling; to forskellige tråde, der får adgang til to forskellige samlinger, vil få lov til at fortsætte samtidigt.

Dit første eksempel er ikke-trivielt. Grunden til, at det virker, er, at strengobjektet initialiseres til en streng-literal. På grund af literal's internering vil alle tråde, der kommer ind i funktionen, opnå den samme String objekt, så den synkroniserede blok vil beskytte monitorsektionen korrekt.


Java tag