<?xml version="1.0" encoding="UTF-8"?>
<posts type="array">
  <post>
    <body>Jeg er midt i en debugsession i en Java applikation som n&#230;gter at virke. Maskinen er en 64bit server med 16 fysiske CPU'er. Efter et par timer g&#229;r det op for mig at Java&#8217;s threadlocal er &#229;rsagen. Applikationen k&#248;re fint p&#229; en dual core maskine hvor CPU&#8217;er har f&#230;lles hukommelse men kan ikke k&#248;re p&#229; en maskine hvor alle CPU&#8217;er har hver deres hukommelse. Jeg g&#229;r ud fra at det underliggende operativsystem skifter CPU hvorefter min Java proces mister sin kontekst.   

ThreadLocal er en slags global variable allokeret til en tr&#229;d p&#229; en m&#229;de s&#229; den er synlig for alle objekter der eksekveres i denne i denne tr&#229;d. Denne metode benyttes ofte til at binde fx bruger-id eller transaction-id til en tr&#229;d og i meget sj&#230;ldent tilf&#230;lde en database forbindelse. I dette tilf&#230;lde er det det sidste. 

Hvis man kigger ind i threadlocal klassen finder man en n&#248;gle med v&#230;rdien 0x61c88647 og alle nye objekter af denne type tildeles v&#230;rdien hash_increment plus v&#230;rdien 0x61c88647.   Alts&#229;, v&#230;rdien 0x61c88647 er jo et tal i 16tals formatet og hvis man oms&#230;tter det til et decimaltal f&#229;r man enten 2654435769 eller -1640531527. Det er en 32-bit signed version af den usignerede 2654435769 og er den faktiske v&#230;rdi som Java bruger til at beregne hash. 

Tallet repr&#230;senterer &#8221;The Golden Section&#8221; eller den gyldne ratio(sqrt (5) -1) gange to til potensen af 31. Check Dr Ron Knott algoritmer og Donald Knuth, de b&#248;ger h&#248;rer hjemme hos en enhver seri&#248;s programm&#248;r. M&#229;ske ogs&#229; Merck Manual &#8221;adorns your health practitioner's&#8221;. 

Koden for threadlocal en smule kompliceret og jeg m&#229; ty til Dr Heinz for en forklaring. Tanken bag tidligere versioner af Java threadlocals var at dele state mellem flere tr&#229;de hvilket g&#248;r dem praktisk talt ubrugelige for multi-core-applikationer. I Java 1.4, blev et nyt design introduceret hvori threadlocals blev opbevaret direkte i den eksekverede tr&#229;d. N&#229;r man kalder metoden get() sker det p&#229; tr&#229;den og der returneres en instans af threadlocalmap som er en slags indre klasse af threadlocal.  I teorien skulle en udg&#229;ende tr&#229;d fjerne sine threadlocal v&#230;rdier lige f&#248;r garbage collection kaldes med exit() metoden. Hvis vi derimod glemme at fjerne en threadlocal er den stadig berettiget til automatisk garbage collection. Det skyldes en weak references intern i threadlocal til threadlocalmap der har normalt st&#230;rke henvisninger til v&#230;rdier.

Et threadlocal objekt bliver garbage collected n&#229;r den eksekverede tr&#229;d d&#248;r. Undtagen hvis tr&#229;den er blevet trukket ud af en objekt pool som fx i nogle applikationsserverer, i disse tilf&#230;lde bliver v&#230;rdierne aldrig garbage collected.    

N&#229;r et threadlocal objekt bliver garbage collected bliver den svage reference threadlocalmap ryddet. Hvorn&#229;r bliver det s&#229; virkeligt slettet fra threadlocalmap. N&#229;r vi kalder get() metoden p&#229; en indgang i java.util.WeakHashMap fjernes alle gamle indgange. Hvis vi kalder get() p&#229; threadlocalmap g&#229;r det hurtigere men kan give for&#230;ldet poster og dermed memory leaks.

N&#229;r man kalder ThreadLocal set() kan det falde ind under disse kategorier:     

# hvis v&#230;rdi ikke findes inds&#230;ttes den. 
# hvis vi finder vores n&#248;gle, byttes den med ny v&#230;rdi.
# hvis der ikke er plads til flere v&#230;rdier. Denne fase bruger en O(log2n) algoritmen i f&#248;rste omgang. 
# hvis en n&#248;glen er fjernet s&#229; er posten slettet. 

Hvis du &#248;nsker flere oplysninger om, hvordan det virker, kan du f&#229; nogle ideer fra Knuth 6.4 AlgoritmeR. 

Best Practices hvis du absolut vil bruge threadlocals skal du s&#248;rge for at fjerne de indsatte v&#230;rdier n&#229;r du er f&#230;rdig med dem, og helst inden du afleverer din tr&#229;d til en tr&#229;d pool. Den bedste m&#229;de at g&#248;re dette p&#229; er at bruge metoden remove() i stedet for set(null) som vil medf&#248;re at weak reference mappe bliver fjernes straks sammen med v&#230;rdien.  

</body>
    <category-id type="integer" nil="true"></category-id>
    <created-at type="datetime">2008-11-17T22:19:08Z</created-at>
    <id type="integer">126</id>
    <post-id type="NilClass">126</post-id>
    <published type="boolean">true</published>
    <tag-id type="NilClass">48</tag-id>
    <title>Threadlocal storage</title>
    <updated-at type="datetime">2008-11-17T22:21:13Z</updated-at>
  </post>
  <post>
    <body>Jeg skal hastighedsoptimere en Java applikation. Den skal performe max p&#229; kortest mulige tid. Den kan ikke skalere udad som man normalt ville &#248;nske men kun opad. Det vil sige en enkelt supermaskine med 16 CPU'er og 16G ram i 64bit software. 

I de senere &#229;r er kravet om hurtigere CPU hastigheder er faldet mens kravet om antal CPU'er er steget. Grunden er at en hurtig processor bruger mere str&#248;m end to processorer p&#229; den samme kraft og man udnytter alts&#229; forholdet mellem ydeevne og forbrug.

Problemet med at skalere en Java applikation er f&#248;rst og fremmest at Java ikke kan udnytte en &#230;gte multicore arkitektur s&#229; den &#248;nskede effektivitet kan opn&#229;s. Man kan tilf&#248;re s&#229; mange CPU'er man vil men Java kan ikke udnytte dem. Dog kan man sige at sige at Java processerne f&#229;r mere frihed idet de andre processer p&#229; maskinen som fx databaser kan k&#248;re p&#229; andre cores. 

Selve Java applikationen er en heterogen monolitisk struktur og den skal eksekveres som en 32bit applikation. Det vil sige at den kun kan udnytte 2G hukommelse eller mindre. Det betyder desv&#230;rre ogs&#229; at man skalere p&#229; den laveste f&#230;llesn&#230;vner. 

Men hvad sker der n&#229;r man flytter en applikation fra en dual core maskine til en &#230;gte fysisk 16 core maskine? Min interesse i sagen er kun henvendt p&#229; i hvilken udtr&#230;kning Java kan udnytte de mange processorer. Hvis Java kun kan udnytte en processor m&#229; applikationen kunne k&#248;re p&#229; samme vis som p&#229; andre duals maskiner. Hvad ville der ske hvis Java kunne udnytte flere CPU&#8217;er og de enkelte processer uds&#230;ttes for &#230;gte samtidighed, alts&#229; potentielt mange samtidige eksekvererne tr&#229;de i samme objekt?   

To ting vakte min opm&#230;rksomhed. Dels en memory leak og dels en slags forvirring omkring konfiguration og resourcer som fx databaseforbindelser. Memory leaks i applikationen skyldes bla ikke frigjorte v&#230;rdier fra hukommelsen. Den andre adf&#230;rd var mere underlig. Applikationen kunne k&#248;re skiftevis langt f&#248;r en tilstand reageret p&#229; manglede resourcer.  

Til min store overraskelses opdager jeg efter flere timers debug session at problemet ligger i ThreadLocal objektet i Java eller rettere dem m&#229;de man bruger dem p&#229;. Applikations designeren binder databaseforbindelser i disse tr&#229;d relaterede objekter. N&#229;r en container tr&#229;d d&#248;r tager den de lokale objekter med sig. Men n&#229;r 64bit maskinen bestemmes sig for at skifte CPU mister alle threadlocals konteksts. Det betyder at konfiguration og resources bliver frigivet midt i k&#248;rselen. 

ThreadLocal har v&#230;ret en meget brugt strategi gennem mange &#229;r og benyttes til at b&#230;re fx et ID gennem en applikation b&#229;de i en tr&#229;d men jeg vil p&#229;st&#229; at det er et antipattern at benytte den til andet fx databaseforbindelser. 

l&#230;s: Thread-local storage

Efter udbedrelse af problemerne k&#248;re softwaren fint p&#229; 64bit maskinen. Java installationen bruger to, m&#229;ske tre CPU'er til at eksekvere Java softwaren. N&#229;r man skalere er det &#248;nskeligt at kunne skalere line&#230;rt, alts&#229; ved en fordobling af kraft for&#248;ger man hastighed gange to. Reelt set k&#248;re denne Java applikation p&#229; en af de 16 hurtige CPU ad gange og udnyttelsen af den fine hardware stinker max. 

Hvis man vil kunne skalere sine applikationer m&#229; man skrive dem til multicore.

&quot;Small Things, Loosely Joined, Written Fast&quot;:posts/122-Small-Things-Loosely-Joined-Written-Fast</body>
    <category-id type="integer" nil="true"></category-id>
    <created-at type="datetime">2008-11-01T09:51:34Z</created-at>
    <id type="integer">124</id>
    <post-id type="NilClass">124</post-id>
    <published type="boolean">true</published>
    <tag-id type="NilClass">48</tag-id>
    <title>Scaling Enterprise Java on 64-bit MultiCore</title>
    <updated-at type="datetime">2008-11-02T22:50:31Z</updated-at>
  </post>
</posts>
