ThreadLocal詳解
- 一、故事背景
- 二、知識點主要構成
- 1、什么是ThreadLocal?
- 2、ThreadLocal的基本使用
- 內存泄漏問題
- 引用類型:
- 強引用:
- 軟引用
- 弱引用
- 虛引用
- ThreadLocal內存泄漏原因
- 三、總結提升
一、故事背景
最近在學習并發編程相關內容,這里給大家分享一下ThreadLocal如何使用以及不規范的使用ThreadLocal可能會造成的問題。
二、知識點主要構成
1、什么是ThreadLocal?
ThreadLocal叫做線程變量,意思是ThreadLocal中填充的變量屬于當前線程,該變量對其他線程而言是隔離的,也就是說該變量是當前線程獨有的變量。ThreadLocal為變量在每個線程中都創建了一個副本,那么每個線程可以訪問自己內部的副本變量。
ThreadLoal 變量,線程局部變量,同一個 ThreadLocal 所包含的對象,在不同的 Thread 中有不同的副本。因為每個 Thread 內有自己的實例副本,且該副本只能由當前 Thread 使用。這是也是 ThreadLocal 命名的由來。既然每個 Thread 有自己的實例副本,且其它 Thread 不可訪問,那就不存在多線程間共享的問題。ThreadLocal 提供了線程本地的實例。它與普通變量的區別在于,每個使用該變量的線程都會初始化一個完全獨立的實例副本。
2、ThreadLocal的基本使用
public class ThreadLocalDemo02 {private ThreadLocal<Person> threadLocal = new ThreadLocal<>();public Person getContent() {return threadLocal.get();}public void setContent(Person person) {threadLocal.set(person);}public static void main(String[] args) {ThreadLocalDemo02 threadLocalDemo02 = new ThreadLocalDemo02();Person person = new Person();person.setName("wmj");new Thread(() ->{threadLocalDemo02.setContent(person);System.out.println(threadLocalDemo02.getContent());}).start();try {Thread.sleep(500);} catch (InterruptedException e) {throw new RuntimeException(e);}new Thread(()->{System.out.println(threadLocalDemo02.getContent());}).start();}
}
內存泄漏問題
在介紹ThreadLocal造成的內存泄漏問題之前先給大家介紹一下Java中的四種引用類型:
引用類型:
強引用:
最常見的普通對象引用,只要還有一個強引用指向一個對象,就能表明對象還活著,垃圾回收器就不會回收這種對象;
public class Client {public static void main(String[] args) {M m = new M();m = null;System.gc();}
}
軟引用
內存不足時則會觸發gc清理軟引用
public class TestSoftReference {public static void main(String[] args) {//軟引用SoftReference<byte[]> softReference = new SoftReference<>(new byte[1024 * 1024 * 10]);System.out.println(softReference.get());System.gc();try {Thread.sleep(500);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(softReference.get());byte[] bytes = new byte[1024 * 1024 * 12];System.out.println(softReference.get());}
}
弱引用
GC一旦發現里只具有弱引用的對象,不管當前內存空間是否足夠,都會回收它的內存;
public class WeakDemo {public static void main(String[] args) {WeakReference wr = new WeakReference(new Person());System.out.println(wr.get());System.gc();try {Thread.sleep(1000);} catch (InterruptedException e) {throw new RuntimeException(e);}System.out.println(wr.get());}
}
虛引用
虛引用大多被用于引用銷毀前的處理工作,本次暫不介紹關于虛引用的詳細操作。
ThreadLocal內存泄漏原因
ThreadLocal提供了線程的局部變量,每個線程都可以通過set()和get()來對這個局部變量進行操作,但不會和其他線程的局部變量進行沖突,實現了線程的數據隔離。
Thread為每個線程維護了ThreadLocalMap這么一個Map,而ThreadLocalMap的key是LocalThread對象本身,value則是要存儲的對象。
而key被保存到了弱引用WeakReference對象中,ThreadLocal在沒有外部強引用時,發生GC時會被回收(弱引用就是只要JVM垃圾回收器發現了它,就會將之回收),而這個Entry對象中的value就有可能一直得不到回收,那時就會發生內存泄露。
三、總結提升
threadlocl是作為當前線程中屬性ThreadLocalMap集合中的某一個Entry的key值Entry(threadlocl,value),雖然不同的線程之間threadlocal這個key值是一樣,但是不同的線程所擁有的ThreadLocalMap是獨一無二的,也就是不同的線程間同一個ThreadLocal(key)對應存儲的值(value)不一樣,從而到達了線程間變量隔離的目的,但是在同一個線程中這個value變量地址是一樣的。ThreadLocal 適用于每個線程需要自己獨立的實例且該實例需要在多個方法中被使用,也即變量在線程間隔離而在方法或類間共享的場景。
如果本篇博客對您有一定的幫助,大家記得留言+點贊+收藏哦。