Java >> Java tutorial >  >> Tag >> break

At sætte et brudpunkt i en ikke-tilgængelig tråd tvinger den til at køre

Som jeg forventede, da den boolske test ikke er flygtig, bruger Thread1 lokal cacheværdi for testen, og når Thread2 ændrer den til sand, vil Thread1 ikke gøre noget.

Din forventning er forkert.

Ifølge Java Language Specification, hvis en tråd opdaterer en ikke-flygtig delt variabel, og en anden tråd efterfølgende læser den uden passende synkronisering, kan den anden tråd kan se den nye værdi, eller den kan se en tidligere værdi.

Så det, du ser, er tilladt af JLS.

I praksis, når en debug-agent er knyttet til en JVM, vil det typisk få JIT-kompileren til at rekompilere nogle eller alle metoder på et lavere optimeringsniveau ... eller muligvis endda eksekvere dem ved hjælp af bytecode-fortolkeren. Dette vil sandsynligvis ske for metoder med brudpunkter angivet i dem, og når du træder i et enkelt trin 1 . Dette kan resultere i anderledes adfærd for kode, der bruger delte variabler uden ordentlig synkronisering, når du fejlretter den.

Dette er en af ​​grundene til, at fejlfindingsproblemer forårsaget af utilstrækkelig synkronisering er vanskelig.

Så vidt jeg ved, ændrer breakpoints instruktionerne i kode ved at tilføje en speciel fælde kaldet INT 3. Så hvad sker der egentlig?

Det er, hvad der sker, når du fejlretter C/C++. Det er ikke specificeret, hvordan en JVM håndterer dette, men en typisk JVM har andre muligheder for at implementere breakpoints ... på grund af bytekoder og JIT-kompilering.

Når jeg sætter en sleep(1) i Thread1 før hvis erklæring vil den også udskrive linjen. Sker der det samme ved at tilføje en søvn?

sleep vil få den aktuelle tråd til at blive suspenderet. Hvad der sker på implementeringsniveau er ikke specificeret . Det er dog sandsynligt at de native trådmekanismer vil tømme alle udestående skrivninger (dvs. beskidte cache-indgange) for den suspenderede tråd til hukommelsen ... som en del af processen med at udføre en trådkontekstskift.

På samme måde, hvis du bruger print-sætninger, har en typisk I/O-stak intern synkronisering, der kan udløse cache-tømninger osv. Dette kan også ændre adfærden for den kode, som du forsøger at debugge.

Jeg skal dog understrege, at denne adfærd ikke er specificeret.

1 - En JIT optimizer har lov til at omarrangere tildelinger, forudsat at dette ikke ændrer enkelttrådsadfærd. Men hvis du fejlfinder en metode og observerer, at værdier af variabler, er virkningerne af genbestillingen synlige (for programmøren). Deoptimering/tolkning undgår dette. Heldigvis kan en moderne JVM/debug-agent gøre dette "on the fly" efter behov.


Advarsel: dette svar er for det meste baseret på, hvordan .Net-debuggere fungerer, men jeg forventer lignende adfærd mellem to kørselstider. Jeg forventer, at JVM tillader per-metode gen-JIT-ing på køretid, da den allerede kan erstatte metoden med HotSpot JIT.

Der er nogle eksisterende artikler og indlæg om, hvilke optimeringer der er slået fra for fejlretning som AMD:perf, når fejlretning er aktiveret, Bivirkninger ved at køre JVM i fejlretningstilstand, Vil Java-appen blive langsommere ved tilstedeværelse af -Xdebug eller kun, når du træder gennem kode? . De antyder, at i det mindste, når der er en undtagelse, tager kode en væsentlig anden kodesti under debugger, hvilket kan være hvordan breakpoints implementeres.

Mange debuggere slår optimeringer fra (kompileringstid, hvis du tillader at genkompilere kode og JIT-tid, hvis du fejlfinder eksisterende kode), når du debugger koden. I .Net-verdenen er virkningen global - når debugger er tilsluttet, kan den skifte alle fremtidige JIT-kompilationer til ikke-optimeret sti, jeg forventer, at Java/JVM understøtter mere granulær kontrol for kun at tillade de-optimering af metoder, der muligvis skal stoppe i debugger. Dette gøres for at give dig mulighed for tydeligt at se alle værdier af alle variabler. Ellers er halvdelen af ​​informationen nogle gange inklusive metodekald og lokale/medlemsvariabler ikke tilgængelig.

"bruger lokal cacheværdi af test" er optimering (sandsynligvis på JIT-tidspunkt) - så når du begynder at fejlfinde koden (eller aktiverer en form for step-through med breakpoints), vil den slå optimering fra og læse fra hukommelsen hver gang, hvilket i det væsentlige gør variabel tæt på volatile (stadig ikke nødvendigt at opføre sig sådan hele tiden men tæt på).

Afhængigt af debugger du bruger, kan du deaktivere sådan adfærd (men fejlretning vil være meget sværere).


Java tag