static final ThreadLocal ตัวแปรคือเธรดปลอดภัย
staticทำให้ตัวแปร ThreadLocal พร้อมใช้งานในหลายคลาสสำหรับเธรดที่เกี่ยวข้องเท่านั้น เป็นการแยกตัวแปร Global ชนิดหนึ่งของตัวแปรโลคัลเธรดที่เกี่ยวข้องในหลายคลาส
เราสามารถตรวจสอบความปลอดภัยของเธรดนี้ด้วยตัวอย่างโค้ดต่อไปนี้
CurrentUser - เก็บ ID ผู้ใช้ปัจจุบันใน ThreadLocal
TestService- บริการง่ายๆด้วยวิธีการ - getUser()เพื่อดึงผู้ใช้ปัจจุบันจาก CurrentUser
TestThread - คลาสนี้ใช้สำหรับสร้างเธรดหลายเธรดและตั้งค่าผู้ใช้พร้อมกัน
.
public class CurrentUser
public class CurrentUser {
private static final ThreadLocal<String> CURRENT = new ThreadLocal<String>();
public static ThreadLocal<String> getCurrent() {
return CURRENT;
}
public static void setCurrent(String user) {
CURRENT.set(user);
}
}
public class TestService {
public String getUser() {
return CurrentUser.getCurrent().get();
}
}
.
import java.util.ArrayList;
import java.util.List;
public class TestThread {
public static void main(String[] args) {
List<Integer> integerList = new ArrayList<>();
//creates a List of 100 integers
for (int i = 0; i < 100; i++) {
integerList.add(i);
}
//parallel stream to test concurrent thread execution
integerList.parallelStream().forEach(intValue -> {
//All concurrent thread will set the user as "intValue"
CurrentUser.setCurrent("" + intValue);
//Thread creates a sample instance for TestService class
TestService testService = new TestService();
//Print the respective thread name along with "intValue" value and current user.
System.out.println("Start-"+Thread.currentThread().getName()+"->"+intValue + "->" + testService.getUser());
try {
//all concurrent thread will wait for 3 seconds
Thread.sleep(3000l);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
//Print the respective thread name along with "intValue" value and current user.
System.out.println("End-"+Thread.currentThread().getName()+"->"+intValue + "->" + testService.getUser());
});
}
}
.
เรียกใช้คลาสหลักของ TestThread เอาต์พุต -
Start-main->62->62
Start-ForkJoinPool.commonPool-worker-2->31->31
Start-ForkJoinPool.commonPool-worker-3->81->81
Start-ForkJoinPool.commonPool-worker-1->87->87
End-main->62->62
End-ForkJoinPool.commonPool-worker-1->87->87
End-ForkJoinPool.commonPool-worker-2->31->31
End-ForkJoinPool.commonPool-worker-3->81->81
Start-ForkJoinPool.commonPool-worker-2->32->32
Start-ForkJoinPool.commonPool-worker-3->82->82
Start-ForkJoinPool.commonPool-worker-1->88->88
Start-main->63->63
End-ForkJoinPool.commonPool-worker-1->88->88
End-main->63->63
...
สรุปการวิเคราะห์
- เธรด "main" เริ่มต้นและตั้งค่าผู้ใช้ปัจจุบันเป็น "62" แบบขนาน "ForkJoinPool.commonPool-worker-2" เธรดเริ่มต้นและตั้งค่าผู้ใช้ปัจจุบันเป็น "31" คู่ขนาน "ForkJoinPool.commonPool-worker-3" เธรดเริ่มต้นและตั้งค่าปัจจุบัน ผู้ใช้เป็น "81" คู่ขนาน "ForkJoinPool.commonPool-worker-1" เธรดเริ่มต้นและตั้งค่าผู้ใช้ปัจจุบันเป็น "87" Start-main-> 62-> 62 Start-ForkJoinPool.commonPool-worker-2-> 31-> 31 Start-ForkJoinPool.commonPool-worker-3-> 81-> 81 Start-ForkJoinPool.commonPool-worker-1-> 87-> 87
- เธรดข้างต้นทั้งหมดนี้จะเข้าสู่โหมดสลีปเป็นเวลา 3 วินาที
mainการดำเนินการสิ้นสุดและพิมพ์ผู้ใช้ปัจจุบันเป็น "62" ForkJoinPool.commonPool-worker-1การดำเนินการแบบคู่ขนานจะสิ้นสุดลงและพิมพ์ผู้ใช้ปัจจุบันเป็น "87" ForkJoinPool.commonPool-worker-2สิ้นสุดการดำเนินการแบบคู่ขนานและพิมพ์ผู้ใช้ปัจจุบันเป็น "31" ForkJoinPool.commonPool-worker-3การดำเนินการแบบคู่ขนานจะสิ้นสุดลงและพิมพ์ผู้ใช้ปัจจุบันเป็น "81"
การอนุมาน
เธรดพร้อมกันสามารถดึงข้อมูลผู้ใช้ที่ถูกต้องได้แม้ว่าจะมีการประกาศว่าเป็น "ThreadLocal สุดท้ายแบบคงที่" ก็ตาม