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

Hvordan sammenligner Java Synchronized låste objekter?

Låser synchronized(obj) baseret på objektets hukommelsesplacering eller dets toHash()-funktion?

Ingen af ​​dem. Den låser på skærmen, der er knyttet til objektet. Med hensyn til JVM taler vi ikke om et objekts hukommelsesadresse, fordi det kan flyttes, og det er ikke hash-koden (selv med hensyn til Object.hashcode() ), fordi det ikke er unikt.

Med hensyn til hvad du bør være låst på, skal det være den samme final objekt. Noget som:

private final Object lockObject = new Object();
...
synchronized (lockObject) {
   // do stuff that needed to be protected
}

Du vil have det til at være final så flere tråde kan garanteres at låse på den samme objektreference, som ikke ændrer sig. private er god, så uden for klasser kan man ikke skrue op for låsningen inde i en klasse.

Her har "asdf" en unik hash, men ingen unik hukommelsesadresse.

"asdf" gør ikke har en unik hash, da andre strenge måske har den samme hash, og det faktisk kan har en unik "hukommelsesadresse" på tværs af al brug af "asdf" i din applikation, hvis compileren gemmer den i Java-strengpuljen. Det betyder, at en helt anden klasse muligvis også har den samme dårlige mønsterkodeblok og vil påvirke synkroniseringen af ​​din klasse, fordi den ville låse på den samme String objektforekomst. Det er derfor en private låseobjekt er så vigtigt.

Mens vi er på emnet, må du heller aldrig synkronisere på en foranderlig værdi som et ikke-endeligt objekt som Boolean eller Integer . Følgende mønster bruges ofte og er meget forkert:

Boolean value = false;
...
// really bad idea
synchronized (value) {
   if (value) {
      value = false;
   } else {
      value = true;
   }
}

Dette er meget forkert fordi value referencen ændrer sig. Så en tråd kan låse på den og derefter ændre dens referenceværdi, så en anden tråd låser på et andet objekt, og begge tråde vil være inden for synchronized på samme tid. Det er endnu værre, fordi med en Boolean der er kun 2 værdier af true og false som er konstanter, så flere klasser ville så låse på de samme referencer.


Du synkroniserer over et objekt, problemet med hukommelsesadressen er udelukkende en implementering og vedrører dig ikke. Så længe det er det samme objekt (hvilket betyder nøjagtig samme instans), er synkroniseringen udført.

Hvis du bruger en anden instans, fungerer synkroniseringen ikke. Det du kan gøre er at definere en offentlig statisk konstant som låsen :

public final static Object LOCK = new Object();

og brug det

synchronized(SomeClass.LOCK) {

Java tag