ข้อควรระวัง: การตรึงและ ThreadLocals
หลีกเลี่ยงการบล็อกเธรดพาหะ
ข้อควรระวัง: การตรึงและ ThreadLocals เป็นบทเรียน Java Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Java Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน
สิ่งที่อาจผิดพลาดได้
เธรดเสมือนมีประสิทธิภาพสูง แต่ข้อควรระวังสองประการอาจบั่นทอนความสามารถในการรองรับการขยายได้อย่างเงียบ ๆ ได้แก่ การตรึงเธรดและการใช้ ThreadLocals มากเกินไป
บทเรียนนี้จะอธิบายทั้งสองเรื่องและวิธีหลีกเลี่ยง
การตรึงเธรดคืออะไร
การตรึงเธรดเกิดขึ้นเมื่อเธรดเสมือนไม่สามารถถอดออกจากเธรดพาหะขณะกำลังรอแบบขัดขวางได้ เธรดของ OS ที่เป็นพาหะจะยังคงติดอยู่ ทำลายประโยชน์ด้านความสามารถในการรองรับการขยาย
เมื่อมีเธรดพาหะถูกตรึงมากเกินไป ปริมาณงานที่ประมวลผลได้จะลดลงอย่างรวดเร็ว
สาเหตุ: การรอแบบขัดขวางใน synchronized
สาเหตุทั่วไปคือการรอแบบขัดขวางภายในบล็อกหรือวิธีการ synchronized ขณะถือครองมอนิเตอร์แล้วเข้าสู่ภาวะรอ เธรดเสมือนจะยังคงถูกตรึงไว้กับเธรดพาหะ
หมายเหตุ: ตั้งแต่ JDK 24 ขึ้นไป (JEP 491) ข้อจำกัดนี้ถูกนำออกไปเป็นส่วนใหญ่แล้ว แต่ใน Java 21 ยังคงเป็นข้อควรระวังที่สำคัญ
ตัวอย่างการตรึงเธรดที่ควรหลีกเลี่ยง
รูปแบบนี้อาจทำให้เกิดการตรึงเธรดใน Java 21 นั่นคือการรอแบบขัดขวางขณะถือครองมอนิเตอร์ โค้ดยังคงทำงานได้อย่างถูกต้อง แต่ไม่สามารถรองรับการขยายได้
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)");
}
}วิธีแก้: ReentrantLock
แทนที่ synchronized ด้วย ReentrantLock เมื่อส่วนวิกฤตอาจเข้าสู่ภาวะรอแบบขัดขวาง ส่วนติดต่อสำหรับล็อกเป็นมิตรต่อเธรดเสมือนและเปิดให้ถอดเธรดออกได้
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");
}
}การวินิจฉัยการตรึงเธรด
คุณสามารถสั่งให้ JVM พิมพ์ร่องรอยสแตกทุกครั้งที่เกิดการตรึงเธรดได้โดยเปิดใช้งานด้วย:
-Djdk.tracePinnedThreads=fullสำหรับร่องรอยทั้งหมด-Djdk.tracePinnedThreads=shortสำหรับผลลัพธ์แบบบรรทัดเดียว
วิธีนี้ช่วยให้คุณค้นหาส่วน synchronized ที่เป็นต้นเหตุได้
ThreadLocals มีต้นทุนสูงขึ้น
ThreadLocal เก็บสถานะเฉพาะเธรดไว้ สำหรับเธรดแพลตฟอร์มไม่กี่เธรด เรื่องนี้ไม่มีปัญหา แต่เมื่อมีเธรดเสมือนหลายล้านเธรดและแต่ละเธรดมีสำเนาของตนเอง การใช้หน่วยความจำจะเพิ่มขึ้นอย่างมาก
ตรวจสอบไลบรารีของคุณ: การเก็บข้อมูลไว้ใช้ซ้ำ การจัดรูปแบบ และวัตถุบริบทมักซ่อน ThreadLocals ไว้ภายใน
ThreadLocal ยังคงใช้งานได้
ไม่ได้ห้ามใช้ ThreadLocal เพียงแต่ควรใช้เท่าที่จำเป็น เธรดเสมือนแต่ละเธรดจะได้รับค่าของตนเองตามที่คาดไว้
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();
}
}ควรเลือกใช้ ScopedValue
Java เพิ่ม ScopedValue เป็นทางเลือกที่ใช้ทรัพยากรน้อยกว่าสำหรับแบ่งปันข้อมูลที่ไม่เปลี่ยนแปลงและมีอายุการใช้งานที่จำกัดขอบเขต วิธีนี้หลีกเลี่ยงต้นทุนของพื้นที่เก็บข้อมูลแบบเปลี่ยนแปลงได้ต่อเธรดของ ThreadLocal และเข้ากับรูปแบบการทำงานพร้อมกันแบบมีโครงสร้าง
เมื่อคุณเพียงต้องส่งบริบทแบบอ่านอย่างเดียวลงไปตามสายการเรียกใช้ ให้เลือกใช้สิ่งนี้แทน
อย่ารวมเธรดเป็นกลุ่ม
ข้อควรระวังอีกประการหนึ่งคือการปฏิบัติต่อเธรดเสมือนราวกับเป็นทรัพยากรหายากแล้วรวมไว้เป็นกลุ่ม วิธีดังกล่าวทำให้เกิดการแย่งใช้ทรัพยากรและการรั่วไหลของ ThreadLocal ระหว่างงานขึ้นมาอีกครั้ง
สร้างเธรดเสมือนหนึ่งเธรดต่องานเสมอ แล้วปล่อยให้เธรดสิ้นสุดการทำงาน
รายการตรวจสอบเพื่อรองรับการขยาย
ก่อนนำเธรดเสมือนไปใช้จริง:
- แทนที่
synchronizedที่มีการรอแบบขัดขวางด้วยReentrantLock - เปิดใช้
jdk.tracePinnedThreadsในการทดสอบ - ลดการใช้
ThreadLocalและเลือกใช้ScopedValueแทน - อย่ารวมเธรดเสมือนเป็นกลุ่ม
ตรวจสอบความเข้าใจอย่างรวดเร็ว
ระบุสิ่งทดแทนที่ปลอดภัยสำหรับบล็อก synchronized ที่มีการรอแบบขัดขวาง
สรุป
คุณได้เรียนรู้ข้อควรระวังหลักแล้ว:
- การตรึงเธรด: การรอแบบขัดขวางภายใน
synchronizedทำให้เธรดพาหะไม่ว่าง แก้ไขด้วยReentrantLock - วินิจฉัยด้วย
-Djdk.tracePinnedThreads - ต้นทุนของ ThreadLocal เพิ่มขึ้นตามจำนวนเธรด ควรเลือกใช้
ScopedValueแทน - อย่ารวมเธรดเสมือนเป็นกลุ่ม
หลักสูตรเธรดเสมือนจบลงเพียงเท่านี้
เรียนรู้ Java ด้วย AI tutor — ฟรี
เขียนและเรียกใช้โค้ดจริงในเบราว์เซอร์ของคุณ รับความช่วยเหลือทันทีจาก AI tutor 24/7 และเรียนรู้ต่อจากที่คุณหยุดบนเว็บหรือในแอป
- คอร์ส
- 104
- บทเรียน
- 374
คำถามที่พบบ่อย
บทเรียน “ข้อควรระวัง: การตรึงและ ThreadLocals” ฟรีหรือไม่
ใช่ — ข้อความเต็มของ “ข้อควรระวัง: การตรึงและ ThreadLocals” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Java Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Java Academy มีบทเรียนทั้งหมด 4 บทเรียน
คุณจะเรียนรู้อะไรในบทเรียน “ข้อควรระวัง: การตรึงและ ThreadLocals”
หลีกเลี่ยงการบล็อกเธรดพาหะ คุณปฏิบัติ Java Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน
คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Java Academy หรือไม่
ไม่จำเป็นต้องมีประสบการณ์มาก่อน Java Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน
บทเรียน “ข้อควรระวัง: การตรึงและ ThreadLocals” ใช้เวลานานแค่ไหน
บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย
ฉันเขียนและรันโค้ดในบทเรียน Java Academy นี้ได้ไหม
ได้ บทเรียน Java Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ
บทเรียนทั้งหมดในหลักสูตรนี้
- เธรดเสมือนคืออะไร
- การสร้างเธรดเสมือน
- เธรดแพลตฟอร์มเทียบกับเธรดเสมือน
- ข้อควรระวัง: การตรึงและ ThreadLocals