ThreadLocal을 사용하면 스레드 전용 변수를 만들 수 있습니다. 이 변수는 다른 스레드에 표시되지 않습니다. ThreadLocal은 각 스레드에서 변수의 복사본을 생성하고 각 스레드는 코드 예제인 전용 스레드 변수에 액세스할 수 있습니다.
public class ThreadLocalDemo { //创建一个ThreadLocal对象,用来为每个线程会复制保存一份变量,实现线程封闭 private static ThreadLocal<Integer> localNum = new ThreadLocal<Integer>(){ @Override protected Integer initialValue() { return 1; } }; public static void main(String[] args) { //线程0 new Thread(){ @Override public void run() { localNum.set(1); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } localNum.set(localNum.get()+10); System.out.println(Thread.currentThread().getName()+":"+localNum.get());//11 } }.start(); //线程1 new Thread(){ @Override public void run() { localNum.set(3); try { Thread.sleep(2000); } catch (InterruptedException e) { e.printStackTrace(); } localNum.set(localNum.get()+20); System.out.println(Thread.currentThread().getName()+":"+localNum.get());//23 } }.start(); System.out.println(Thread.currentThread().getName()+":"+localNum.get());//0 } }
위에서 언급한 것처럼 메인 스레드와 새로 생성된 2개의 스레드를 합하면 총 3개의 스레드가 있습니다. 각 스레드에는 자체 전용 변수 1, set() 및 get(이 포함되어 있습니다. ) 메소드를 사용하여 값을 설정하고 가져옵니다. 실행 결과는 다음과 같습니다.
ThreadLocal은 모든 유형의 객체를 허용하고 내부적으로 ThreadLocalMap을 유지 관리하는 일반 클래스입니다. 우리가 사용하는 get(), set() 등은 실제로 이 클래스에서 나옵니다. 개인 값을 기록하기 위해 현재 스레드에 대해 ThreadLocalMap 개체가 생성될 때마다
set() 메서드를 먼저 살펴보겠습니다.
public void set(T value) { //拿到当前线程 Thread t = Thread.currentThread(); //拿到当前线程map ThreadLocalMap map = getMap(t); if (map != null) //存在设置值 map.set(this, value); else //不存在则创建 createMap(t, value); }
void createMap(Thread t, T firstValue) { //threadLocals属性即为此map t.threadLocals = new ThreadLocalMap(this, firstValue); }
그러면 get() 메소드
public T get() { //拿到当前线程 Thread t = Thread.currentThread(); //拿到当前线程对应的map ThreadLocalMap map = getMap(t); //如果已有map if (map != null) { //取值操作, 拿到对应的Entry ThreadLocalMap.Entry e = map.getEntry(this); if (e != null) { @SuppressWarnings("unchecked") T result = (T)e.value; return result; } } //没有map, 则去创建初始化一个map return setInitialValue(); }
private T setInitialValue() { //initialValue()方法返回的value为null T value = initialValue(); //拿到当前线程去创建对应的map Thread t = Thread.currentThread(); ThreadLocalMap map = getMap(t); if (map != null) map.set(this, value); else createMap(t, value); return value; }
ThreadLocal은 ThreadLocalMap의 패키지로 이해될 수 있습니다
ThreadLocalMap에서 ThreadLocal 객체는 약한 참조를 키로 사용합니다
이 경우 ThreadLocal cal 외부의 강력한 참조가 없으면 키는 GC에 의해 재활용될 예정이므로 ThreadLocalMap의 키는 null이 되고 값은 여전히 강력한 참조 체인을 갖습니다.
스레드는 동시에 여러 ThreadLocal을 가질 수 있습니다. 약한 참조인 키가 재활용되면 그 값은 재활용될 수 없으므로 이 ThreadLocal의 수명 주기는 이 스레드만큼 길어지게 됩니다(이 값의 강한 참조 체인은 깨지지 않기 때문입니다). 스레드가 실행을 완료할 때까지) 스레드가 종료되지 않으면 누적된 값도 재활용할 수 없으므로 메모리 누수 문제가 발생합니다
여기서 문제를 해결하는 방법은: 제거() 메서드를 호출하는 것입니다. ThreadLocal을 사용한 후 매번 데이터를 삭제하려면
public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this); }
키의 장단점을 살펴보겠습니다. 참조의 차이점
키를 강력한 참조로 사용하는 경우 키의 수명 주기는 스레드만큼 깁니다. 안정적인 강력한 참조 체인이 있어 재활용할 수 없으므로 약한 참조로 사용되면 GC가 자동으로 재활용하므로 후속 Remove() 메서드에서 더 나은 재활용 가치를 얻을 수 있으므로 일반적으로 설계합니다. ThreadLocal은 비공개 정적이어야 하며, 사용 후 제거() 메서드를 사용하여 수동으로 삭제하세요
위 내용은 Java에서 ThreadLocal 스레드 변수의 구현 원리는 무엇입니까?의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!