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

Hvorfor bruge en ReentrantLock, hvis man kan bruge synkroniseret(dette)?

En ReentrantLock er ustruktureret , i modsætning til synchronized konstruktioner -- dvs. du behøver ikke bruge en blokstruktur til låsning og kan endda holde en lås på tværs af metoder. Et eksempel:

private ReentrantLock lock;

public void foo() {
  ...
  lock.lock();
  ...
}

public void bar() {
  ...
  lock.unlock();
  ...
}

Et sådant flow er umuligt at repræsentere via en enkelt monitor i en synchronized konstruere.

Bortset fra det, ReentrantLock understøtter låseafstemning og afbrydelige låseventer, der understøtter timeout. ReentrantLock har også understøttelse af konfigurerbar retfærdighed politik, der tillader mere fleksibel trådplanlægning.

Konstruktøren for denne klasse accepterer en valgfri retfærdighed parameter. Når indstillet true , under påstand, låse favoriserer at give adgang til den længst ventende tråd. Ellers garanterer denne lås ikke nogen særlig adgangsrækkefølge. Programmer, der bruger retfærdige låse, som mange tråde har adgang til, kan vise lavere samlet gennemløb (dvs. er langsommere; ofte meget langsommere) end dem, der bruger standardindstillingen, men har mindre afvigelser i tider for at opnå låse og garantere mangel på sult. Bemærk dog, at retfærdighed af låse ikke garanterer retfærdig trådplanlægning. Således kan en af ​​mange tråde, der bruger en fair lås, opnå den flere gange i træk, mens andre aktive tråde ikke skrider frem og ikke i øjeblikket holder låsen. Bemærk også, at den utimede tryLock metoden respekterer ikke retfærdighedsindstillingen. Det vil lykkes, hvis låsen er tilgængelig, selvom andre tråde venter.

ReentrantLock kan også være mere skalerbar , der klarer sig meget bedre under højere konkurrence. Du kan læse mere om dette her.

Denne påstand er imidlertid blevet bestridt; se følgende kommentar:

I reentrant-låsetesten oprettes en ny lås hver gang, så der er ingen eksklusiv låsning, og de resulterende data er ugyldige. Desuden tilbyder IBM-linket ingen kildekode til det underliggende benchmark, så det er umuligt at karakterisere, om testen overhovedet blev udført korrekt.

Hvornår skal du bruge ReentrantLock s? Ifølge den developerWorks-artikel...

Svaret er ret simpelt – brug det, når du rent faktisk har brug for noget, det giver den synchronized ikke, som tidsindstillede låseventer, afbrydelige låseventer, ikke-blokstrukturerede låse, flere tilstandsvariabler eller låsepolling. ReentrantLock har også skalerbarhedsfordele, og du bør bruge det, hvis du rent faktisk har en situation, der udviser høj strid, men husk, at langt størstedelen af ​​synchronized blokke udviser næsten aldrig nogen strid, endsige høj strid. Jeg vil råde dig til at udvikle med synkronisering, indtil synkronisering har vist sig at være utilstrækkelig, i stedet for blot at antage, at "ydelsen bliver bedre", hvis du bruger ReentrantLock . Husk, at disse er avancerede værktøjer til avancerede brugere. (Og virkelig avancerede brugere har en tendens til at foretrække de enkleste værktøjer, de kan finde, indtil de er overbevist om, at de simple værktøjer er utilstrækkelige.) Som altid skal du gøre det rigtigt først, og derefter bekymre dig om, hvorvidt du skal gøre det hurtigere eller ej.

Et sidste aspekt, der bliver mere relevant i den nærmeste fremtid, har at gøre med Java 15 og Project Loom. I den (nye) verden af ​​virtuelle tråde ville den underliggende skemalægger være i stand til at fungere meget bedre med ReentrantLock end det er i stand til at gøre med synchronized , det er i hvert fald sandt i den indledende Java 15-udgivelse, men det kan blive optimeret senere.

I den nuværende Loom-implementering kan en virtuel tråd fastgøres i to situationer:når der er en native frame på stakken - når Java-kode kalder ind i native code (JNI), som derefter kalder tilbage til Java - og når den er inde i en synchronized blok eller metode. I disse tilfælde vil blokering af den virtuelle tråd blokere den fysiske tråd, der bærer den. Når det oprindelige opkald er afsluttet, eller monitoren er frigivet (synchronized blok/metode er afsluttet) tråden er frigjort.

Hvis du har en fælles I/O-operation beskyttet af en synchronized , udskift skærmen med en ReentrantLock for at lade din applikation drage fuld fordel af Looms skalerbarhedsboost, selv før vi fikser pinning af skærme (eller endnu bedre, brug den højere ydeevne StampedLock hvis du kan).


ReentrantReadWriteLock er en specialiseret lås, hvorimod synchronized(this) er en generel lås. De ligner hinanden, men ikke helt ens.

Du har ret i, at du kunne bruge synchronized(this) i stedet for ReentrantReadWriteLock men det modsatte er ikke altid sandt.

Hvis du gerne vil forstå bedre, hvad der gør ReentrantReadWriteLock specielt slå nogle oplysninger op om producent-forbruger trådsynkronisering.

Generelt kan du huske den hel-metode-synkronisering og generel synkronisering (ved at bruge synchronized søgeord) kan bruges i de fleste programmer uden at tænke for meget om semantikken i synkroniseringen, men hvis du har brug for at presse ydeevnen ud af din kode, skal du muligvis udforske andre mere finkornede eller specielle synkroniseringsmekanismer.

Forresten, ved at bruge synchronized(this) - og generelt låsning ved hjælp af en offentlig klasseinstans - kan være problematisk, fordi det åbner din kode for potentielle dead-locks, fordi en anden ikke bevidst kan forsøge at låse mod dit objekt et andet sted i programmet.


Fra Oracle-dokumentationssiden om ReentrantLock:

En gensidig udelukkelseslås med samme grundlæggende adfærd og semantik som den implicitte skærmlås, der tilgås ved hjælp af synkroniserede metoder og udsagn, men med udvidede muligheder.

  1. En ReentrantLock ejes af tråden, der sidst blev låst, men endnu ikke låst den op. En trådkaldende lås vil vende tilbage og med succes erhverve låsen, når låsen ikke ejes af en anden tråd. Metoden vender tilbage med det samme, hvis den aktuelle tråd allerede ejer låsen.

  2. Konstruktøren for denne klasse accepterer en valgfri retfærdighed parameter. Når det er sat sandt, under påstand, favoriserer låse at give adgang til den længst ventende tråd . Ellers garanterer denne lås ikke nogen særlig adgangsrækkefølge.

ReentrantLock nøglefunktioner i henhold til denne artikel

  1. Mulighed for at låse afbrydeligt.
  2. Mulighed for timeout, mens du venter på lås.
  3. Kraft til at skabe fair lås.
  4. API for at få en liste over ventende tråd for låsning.
  5. Fleksibilitet til at prøve at låse uden at blokere.

Du kan bruge ReentrantReadWriteLock.ReadLock, ReentrantReadWriteLock.WriteLock for yderligere at opnå kontrol over granulær låsning på læse- og skriveoperationer.

Tag et kig på denne artikel af Benjamen om brugen af ​​forskellige typer ReentrantLocks


Java tag