คลาส ThreadLocal สามารถเข้าใจได้ว่าเป็น ThreadLocalVariable (ตัวแปรโลคัลเธรด) ซึ่งจัดเตรียมอินเทอร์เฟซการเข้าถึงหรือเมธอด เช่น get และ set วิธีการเหล่านี้เก็บสำเนาอิสระสำหรับแต่ละเธรดที่ใช้ตัวแปร ดังนั้น get จะส่งคืนตำแหน่งของการดำเนินการปัจจุบันเสมอ เธรด ค่าล่าสุดที่ตั้งไว้เมื่อเรียกใช้ชุด ThreadLocal<T> สามารถคิดได้ว่ามีวัตถุ Map<Thread,T> ซึ่งเก็บค่าเฉพาะสำหรับเธรดนั้น
โดยสรุป สำหรับปัญหาการแบ่งปันทรัพยากรแบบมัลติเธรด กลไกการซิงโครไนซ์ใช้วิธีการ "แลกเปลี่ยนเวลาเป็นพื้นที่" ในขณะที่ ThreadLocal ใช้วิธีการ "แลกเปลี่ยนพื้นที่สำหรับเวลา" แบบแรกจัดเตรียมสำเนาของตัวแปรสำหรับเธรดที่แตกต่างกันเพื่อจัดคิวการเข้าถึง ในขณะที่แบบหลังจัดเตรียมสำเนาของตัวแปรสำหรับแต่ละเธรด ดังนั้นจึงสามารถเข้าถึงได้พร้อมกันโดยไม่กระทบต่อกัน
จำลอง ThreadLocal
คัดลอกรหัสรหัสดังต่อไปนี้:
นำเข้า java.util.Collections;
นำเข้า java.util.HashMap;
นำเข้า java.util.Map;
SimpleThreadLocal ระดับสาธารณะ <T> {
แผนที่ส่วนตัว <Thread, T> valueMap = คอลเลกชัน
.synchronizedMap(ใหม่ HashMap<Thread, T>());
ชุดโมฆะสาธารณะ (T newValue) {
valueMap.put(Thread.currentThread(), newValue); // ①คีย์คือวัตถุเธรดและค่าคือสำเนาของตัวแปรของเธรดนี้
-
สาธารณะ T รับ () {
เธรด currentThread = Thread.currentThread();
T o = valueMap.get(currentThread); // ② ส่งคืนตัวแปรที่สอดคล้องกับเธรดนี้
if (o == null && !valueMap.containsKey(currentThread)) { // 3.หากไม่มีอยู่ในแผนที่ ให้วางไว้ในแผนที่แล้วบันทึก
o = ค่าเริ่มต้น();
valueMap.put(currentThread, o);
-
กลับหรือ;
-
โมฆะสาธารณะลบ () {
valueMap.remove(Thread.currentThread());
-
ป้องกัน T ค่าเริ่มต้น () {
กลับเป็นโมฆะ;
-
-
UtilityThreadLocal
คัดลอกรหัสรหัสดังต่อไปนี้:
คลาสนับ {
ส่วนตัว SimpleThreadLocal<Integer> นับ = SimpleThreadLocal ใหม่ <Integer>() {
@แทนที่
จำนวนเต็มที่ได้รับการป้องกัน defaultValue () {
กลับ 0;
-
-
จำนวนเต็มสาธารณะเพิ่มขึ้น () {
count.set(count.get() + 1);
กลับ count.get();
-
-
คลาส TestThread ใช้ Runnable {
การนับจำนวนส่วนตัว;
TestThread สาธารณะ (นับจำนวน) {
this.count = นับ;
-
@แทนที่
โมฆะสาธารณะวิ่ง () {
// TODO ต้นขั้ววิธีการสร้างอัตโนมัติ
สำหรับ (int i = 1; i <= 3; i++) {
System.out.println(Thread.currentThread().getName() + "/t" + i
+ "th/t" + count.increase());
-
-
-
TestThreadLocal คลาสสาธารณะ {
โมฆะสาธารณะคงหลัก (สตริง [] args) {
นับนับ = นับใหม่ ();
เธรด t1 = เธรดใหม่ (TestThread ใหม่ (นับ));
เธรด t2 = เธรดใหม่ (TestThread ใหม่ (นับ));
เธรด t3 = เธรดใหม่ (TestThread ใหม่ (นับ));
เธรด t4 = เธรดใหม่ (TestThread ใหม่ (นับ));
t1.เริ่มต้น();
t2.เริ่มต้น();
t3.เริ่มต้น();
t4.เริ่มต้น();
-
-
รหัสการคัดลอกผลลัพธ์จะเป็นดังนี้:
เธรด-0 1 1
เธรด-0 2 2
เธรด-0 3 3
กระทู้-3 1 1
กระทู้-1 1 1
กระทู้-1 2 2
เธรด-2 1 1
กระทู้-1 3 3
เธรด-3 2 2
เธรด-3 3 3
เธรด-2 2 2
เธรด-2 3 3