static final ThreadLocal
변수는 스레드로부터 안전합니다.
static
ThreadLocal 변수를 각 스레드에 대해서만 여러 클래스에서 사용할 수 있도록합니다. 여러 클래스에 걸쳐 각 스레드 로컬 변수의 일종의 전역 변수 탈퇴입니다.
다음 코드 샘플을 사용하여이 스레드 안전성을 확인할 수 있습니다.
CurrentUser
-ThreadLocal에 현재 사용자 ID를 저장합니다.
TestService
-메서드가있는 간단한 서비스 getUser()
-CurrentUser에서 현재 사용자를 가져옵니다.
TestThread
-이 클래스는 여러 스레드를 생성하고 동시에 사용자 ID를 설정하는 데 사용됩니다.
.
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"로 선언 된 경우에도 올바른 사용자 ID를 검색 할 수 있습니다.