Sudenkuopat: pinning ja ThreadLocalit
Vältä kuljettajasäikeiden estämistä.
Sudenkuopat: pinning ja ThreadLocalit on ilmainen Java Academy-oppitunti CoddyKitissä. Tämä on oppitunti 4/4. Voit lukea koko oppitunnin alta ilmaiseksi ja harjoitella sen jälkeen käytännössä selaimessa sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla. Oppitunti kuuluu Java Academy-oppimispolkuun, ja edistymisesi synkronoituu verkon ja CoddyKit-sovelluksen välillä. Java Academy-kurssilla on yhteensä 4 oppituntia.
Mikä voi mennä vikaan
Virtuaalisäikeet ovat tehokkaita, mutta kaksi ongelmakohtaa voi huomaamatta heikentää niiden skaalautuvuutta: pinning ja ThreadLocal-muuttujien liiallinen käyttö.
Tässä oppitunnissa selitetään molemmat ja kerrotaan, miten niitä voi välttää.
Mitä pinning tarkoittaa
Pinning tapahtuu, kun virtuaalisäie ei voi irrottautua kantajasäikeestään estyessään. Kantajana toimiva käyttöjärjestelmäsäie jää jumiin, mikä kumoaa skaalautuvuuden tuoman hyödyn.
Kun liian monet kantajasäikeet ovat kiinnittyneinä, suorituskyky romahtaa.
Syy: estyminen synchronized-rakenteessa
Klassinen syy on estyminen synchronized-lohkon tai -metodin sisällä. Kun virtuaalisäie pitää monitoria hallussaan ja estyy sen jälkeen, se pysyy kiinnittyneenä kantajasäikeeseensä.
Huomautus: JDK 24:ssä ja sitä uudemmissa versioissa (JEP 491) tämä rajoitus poistettiin suurelta osin, mutta Java 21:ssä se on todellinen huolenaihe.
Vältettävä pinning-esimerkki
Tämä rakenne voi aiheuttaa pinningiä Java 21:ssä: estyminen monitorin ollessa hallussa. Koodi toimii edelleen oikein, mutta se ei skaalaudu.
public class Main {
static final Object lock = new Object();
static void risky() {
synchronized (lock) {
try { Thread.sleep(10); } catch (InterruptedException e) {}
}
}
public static void main(String[] args) throws InterruptedException {
Thread t = Thread.ofVirtual().start(Main::risky);
t.join();
System.out.println("Done (but this blocked inside synchronized)");
}
}Korjaus: ReentrantLock
Korvatkaa synchronized ReentrantLock-lukolla, kun kriittinen osio voi estyä. Lukkojen ohjelmointirajapinnat sopivat virtuaalisäikeille ja sallivat niiden irrottautumisen kantajasäikeestä.
import java.util.concurrent.locks.ReentrantLock;
public class Main {
static final ReentrantLock lock = new ReentrantLock();
static void safe() {
lock.lock();
try {
try { Thread.sleep(10); } catch (InterruptedException e) {}
} finally {
lock.unlock();
}
}
public static void main(String[] args) throws InterruptedException {
Thread t = Thread.ofVirtual().start(Main::safe);
t.join();
System.out.println("Done without pinning");
}
}Pinningin diagnosointi
Voitte pyytää JVM:ää tulostamaan pinningiä esiintyessä pinon jäljityksen käynnistämällä ohjelman seuraavasti:
-Djdk.tracePinnedThreads=fulltäydellisiä jäljityksiä varten-Djdk.tracePinnedThreads=shortyksirivisiä tietoja varten
Näin löydätte ongelmalliset synchronized-osiot.
ThreadLocalit käyvät kalliiksi
ThreadLocal tallentaa säiekohtaista tilaa. Muutaman alustasäikeen tapauksessa se ei ole ongelma. Kun virtuaalisäikeitä on miljoonia ja jokainen sisältää oman kopionsa, muistin käyttö kasvaa valtavasti.
Tarkistakaa kirjastonne: välimuistit, muotoilu ja kontekstioliot piilottavat usein ThreadLocal-muuttujia.
ThreadLocal toimii edelleen
ThreadLocal ei ole kielletty, mutta käyttäkää sitä säästeliäästi. Jokainen virtuaalisäie saa odotetusti oman arvonsa.
public class Main {
static final ThreadLocal<String> CONTEXT = new ThreadLocal<>();
public static void main(String[] args) throws InterruptedException {
Thread t = Thread.ofVirtual().start(() -> {
CONTEXT.set("request-42");
System.out.println("Context: " + CONTEXT.get());
CONTEXT.remove();
});
t.join();
}
}Suosikaa ScopedValuea
Java esitteli ScopedValue-arvon kevyempänä vaihtoehtona muuttumattoman tiedon jakamiseen rajatun elinkaaren ajan. Se välttää ThreadLocalin säiekohtaisen muuttuvan tallennustilan kustannukset ja sopii rakenteisen samanaikaisuuden malliin.
Kun tarvitsette vain välittää vain luku -muotoista kontekstia kutsuketjua pitkin, käyttäkää mieluummin sitä.
Älkää poolittako
Toinen hienovarainen ongelma on kohdella virtuaalisäikeitä niukkana resurssina ja muodostaa niistä pooli. Se palauttaa kilpailutilanteet ja tehtävien välisen ThreadLocal-tietojen vuotamisen.
Luokaa aina yksi virtuaalisäie kutakin tehtävää varten ja antakaa sen päättyä.
Skaalautuvuuden tarkistuslista
Ennen kuin viette virtuaalisäikeet tuotantoon:
- Korvatkaa estävä
synchronizedReentrantLock-lukolla - Ottakaa
jdk.tracePinnedThreadskäyttöön testauksessa - Minimoikaa
ThreadLocal-muuttujien käyttö ja suosikaaScopedValue-arvoa - Älkää koskaan poolittako virtuaalisäikeitä
Pikatarkistus
Tunnistakaa turvallinen korvaaja estävälle synchronized-lohkolle.
Kertaus
Opitte tärkeimmät ongelmakohdat:
- Pinning:
synchronized-rakenteen sisällä estyminen sitoo kantajasäikeen; korjatkaa tilanne käyttämälläReentrantLock-lukkoa - Diagnosoikaa ongelma komennolla
-Djdk.tracePinnedThreads - ThreadLocal-muuttujien aiheuttama kuormitus kasvaa säiemäärän mukana; suosikaa
ScopedValue-arvoa - Älkää koskaan poolittako virtuaalisäikeitä
Tähän päättyy Virtual Threads -kurssi.
Opi Java tekoälytuutorin avulla — ilmaiseksi
Kirjoita ja suorita oikeaa koodia selaimessa, saa välitöntä apua tekoälytuutorilta ympäri vuorokauden ja jatka siitä, mihin jäit, verkossa tai sovelluksessa.
- Kurssit
- 104
- Oppitunnit
- 374
Usein kysytyt kysymykset
Onko oppitunti ”Sudenkuopat: pinning ja ThreadLocalit” ilmainen?
Kyllä – oppitunnin ”Sudenkuopat: pinning ja ThreadLocalit” koko tekstin voi lukea täällä verkossa ilmaiseksi. Jos haluat harjoitella interaktiivisesti sisäänrakennetulla koodieditorilla ja ympäri vuorokauden käytettävissä olevan tekoälytuutorin avulla sekä avata koko Java Academy-kurssin, päivitä CoddyKit PROhon. Java Academy-kurssilla on yhteensä 4 oppituntia.
Mitä opin oppitunnilla ”Sudenkuopat: pinning ja ThreadLocalit”?
Vältä kuljettajasäikeiden estämistä. Harjoittelet Java Academy-aihetta koodilla, jonka suoritat suoraan selaimessa. Ympäri vuorokauden käytettävissä oleva tekoälytuutori vastaa kysymyksiisi oppitunnin aikana.
Tarvitsenko kokemusta aloittaakseni Java Academy-opiskelun?
Aiempi kokemus ei ole tarpeen. CoddyKitin Java Academy-oppimispolku sopii vasta-alkajista edistyneisiin, joten voit aloittaa tästä tai alusta ja edetä omaan tahtiisi. Tämä on oppitunti 4/4.
Kuinka kauan ”Sudenkuopat: pinning ja ThreadLocalit”-oppitunnin suorittaminen kestää?
Useimmat CoddyKitin oppitunnit kestävät noin 5–10 minuuttia. Jokainen oppitunti on lyhyt ja interaktiivinen, joten edistyt tasaisesti ja voit jatkaa siitä, mihin jäit – sekä verkossa että sovelluksessa.
Voinko kirjoittaa ja suorittaa koodia tällä Java Academy-oppitunnilla?
Kyllä. Jokainen Java Academy-oppitunti sisältää sisäänrakennetun koodieditorin, joten voit kirjoittaa ja suorittaa oikeaa koodia suoraan selaimessa ja saada välitöntä palautetta tekoälyltä – paikallista asennusta ei tarvita.
Kaikki tämän kurssin oppitunnit
- Mitä virtuaalisäikeet ovat
- Virtuaalisäikeiden luonti
- Alusta- ja virtuaalisäikeet
- Sudenkuopat: pinning ja ThreadLocalit