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:
-
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 kalderaddValue
og tramper på listen, mens en anden tråd kaldergetSum
. -
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 medthis
) 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.thingyList
påthis.thingyList
, ikkethis
ellerMyClass.class
. Det er fint, hvis en tråd kaldergetThingySum
mens en anden tråd kalderaddNifty
, 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.