목차
목적
학업 기록, 인터뷰 준비
자원
Station B에서 자주 발생하는 면접 질문에 대한 학습 비디오
핵심 결론
스레드 간 리소스 격리, 스레드 내 리소스 공유.
원칙
각 쓰레드에는 ThreadLocalMap 타입의 멤버변수가 존재하는데 자원객체를 저장하는데 사용된다.
① set()을 호출 즉, ThreadLocal 자신을 키로 자원객체를 값으로 하여 현재 쓰레드 의 ThreadLocalMap 에 저장
② get() 호출, 즉 ThreadLocal 자체를 키로 사용하여 현재 스레드에서 연관된 자원 값 찾기
③ remove() 호출, 즉 ThreadLocal 자체를 키로 사용하여 현재 스레드와 연관된 자원 값 제거
코드 데모
/**
* TestThreadLocal: 线程之间资源隔离, 线程内资源共享
*
* @author xiaozhengN [email protected]
* @since 2022-11-27 22:12:39
**/
@Slf4j
public class TestThreadLocal {
public static void main(String[] args) {
test1();
test2();
}
/**
* 多个线程调用, 得到的是自己的Connection对象
*/
private static void test1() {
for (int i = 0; i < 5; i++) {
new Thread(() -> log.info("当前线程: {}, Connection: {}", Thread.currentThread().getName(), Utils.getConnection()), "test1Thread" + (i + 1)).start();
}
}
/**
* 一个线程内调用, 得到的是同一个Connection对象
*/
private static void test2() {
for (int i = 0; i < 3; i++) {
new Thread(() -> {
log.info("当前线程: {}, Connection: {}", Thread.currentThread().getName(), Utils.getConnection());
log.info("当前线程: {}, Connection: {}", Thread.currentThread().getName(), Utils.getConnection());
}, "test2Thread" + (i + 1)).start();
}
}
static class Utils {
// 线程隔离
private static final ThreadLocal<Connection> threadLocal = new ThreadLocal<>();
/**
* 获取连接
*
* @return Connection对象
*/
public static Connection getConnection() {
Connection connection = threadLocal.get();
if (connection == null) {
connection = innerGetConnection();
threadLocal.set(connection);
}
return connection;
}
private static Connection innerGetConnection() {
try {
return DriverManager.getConnection("jdbc:mysql://localhost:3306/bos?useSSL=false", "root", "root");
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
}
}
다른
ThreadLocalMap의 키가 약한 참조로 설계되어야 하는 이유
① 쓰레드는 오랫동안 실행해야 할 수도 있다.(예: 쓰레드 풀의 쓰레드) 키가 더 이상 사용되지 않으면 GC로 재활용해야 한다
.
키 가 null 인지
여부에 따라 값을 해제 메모리를 해제하는 시간은 다음과 같습니다 . , 정적 변수로 사용되므로 GC에서 재활용할 수 없습니다.
참조 리소스
메모리 누수 문제
ThreadLocals 첨자 계산
특수 상수 0x61c88647
0x61c88647