Java >> Java tutorial >  >> Tag >> final

Java:Gøre alle felter enten endelige eller flygtige?

Mens jeg føler mig private final burde sandsynligvis have været standard for felter og variabler med et nøgleord som var gør den foranderlig ved at bruge flygtig, når du ikke har brug for den

  • meget langsommere, ofte omkring 10 gange langsommere.
  • giver dig normalt ikke den trådsikkerhed, du har brug for, men kan gøre det sværere at finde sådanne fejl ved at gøre det mindre sandsynligt, at de dukker op.
  • i modsætning til final hvilket forbedrer klarheden ved at sige, at dette ikke bør ændres ved hjælp af volatile når det ikke er nødvendigt, vil det sandsynligvis være forvirrende, da læseren forsøger at finde ud af, hvorfor det blev gjort flygtigt.

hvis feltet skal ændres (peg på et andet objekt, opdater den primitive værdi), så skal feltet være flygtigt, så alle andre tråde opererer på den nye værdi.

Selvom dette er fint at læse, så overvej denne trivielle sag.

volatile int x;

x++;

Dette er ikke trådsikkert. Da det er det samme som

int x2 = x;
x2 = x2 + 1; // multiple threads could be executing on the same value at this point.
x = x2;

Hvad værre er, er at bruge volatile ville gøre denne slags fejl sværere at finde.

Som yshavit påpeger, er opdatering af flere felter sværere at omgås med volatile for eksempel. HashMap.put(a, b) opdaterer flere referencer.

Blot en synkronisering af metoderne, der får adgang til feltet, er utilstrækkelig, fordi de kan returnere en cachelagret værdi.

synchronized giver dig alle hukommelsesgarantierne på volatile og mere, hvorfor det er væsentligt langsommere.

BEMÆRK:Bare synchronized -at hver metode er heller ikke altid nok. StringBuffer har alle metoder synkroniseret, men er værre end ubrugelige i en multi-threaded kontekst, da dens brug sandsynligvis er udsat for fejl.

Det er for nemt at antage, at opnåelse af trådsikkerhed er som at drysse eventyrstøv, tilføj noget magisk trådsikkerhed, og dine fejl forsvinder. Problemet er, at gevindsikkerheden er mere som en spand med mange huller. Tilslut de største huller, og fejlene kan se ud til at forsvinde, men medmindre du tilslutter dem alle, har du ikke trådsikkerhed, men det kan være sværere at finde.

Med hensyn til synkroniseret vs flygtig, siger dette

Andre mekanismer, såsom læsning og skrivning af flygtige variable og brugen af ​​klasser i java.util.concurrent-pakken, giver alternative måder at synkronisere på.

https://docs.oracle.com/javase/specs/jls/se7/html/jls-17.html


Gør felter du ikke behøver at ændre final er en god idé, uanset trådningsproblemer. Det gør forekomster af klassen lettere at ræsonnere om, fordi du nemmere kan vide, hvilken tilstand den er i.

Med hensyn til at gøre de andre felter til volatile :

Blot en synkronisering af metoderne, der får adgang til feltet, er utilstrækkelig, fordi de kan returnere en cachelagret værdi.

Du vil kun se en cacheværdi, hvis du får adgang til værdien uden for en synkroniseret blok.

Alle adgange skal synkroniseres korrekt. Slutningen af ​​en synkroniseret blok sker med garanti før starten af ​​en anden synkroniseret blok (når der synkroniseres på den samme skærm).

Der er i det mindste et par tilfælde, hvor du stadig skal bruge synkronisering:

  • Du vil gerne bruge synkronisering, hvis du skulle læse og derefter opdatere et eller flere felter atomært.
    • Du kan muligvis undgå synkronisering for visse enkeltfeltopdateringer, f.eks. hvis du kan bruge en Atomic* klasse i stedet for en "almindelig gammel mark"; men selv for en enkelt feltopdatering kan du stadig kræve eksklusiv adgang (f.eks. tilføje et element til en liste, mens du fjerner et andet).
  • Den volatile/finale kan også være utilstrækkelig til ikke-trådsikre værdier, såsom en ArrayList eller en matrix.

Java tag