ThreadLocal membenarkan kami membuat pembolehubah urutan peribadi. Pembolehubah ini tidak dapat dilihat oleh urutan lain pembolehubah. Contoh kod adalah seperti berikut:
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 } }
Seperti yang dinyatakan di atas, mengira utas utama dan dua utas yang baru dibuat, terdapat sejumlah tiga utas Setiap utas mengandungi Pembolehubah peribadinya, di sini kami tetapkan nilai 1. Kaedah set() dan get() digunakan untuk menetapkan dan mendapatkan nilai Hasil pelaksanaan adalah seperti berikut:
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); }
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; }
Dalam kes ini, jika ThreadLocal tidak mempunyai rujukan kuat luaran, maka kunci itu ditakdirkan untuk dikitar semula oleh GC, yang akan menyebabkan kunci dalam ThreadLocalMap menjadi batal dan nilainya masih mempunyai rantai rujukan yang kukuh
Benang boleh Dengan berbilang ThreadLocals pada masa yang sama, jika kunci sebagai rujukan lemah dikitar semula, nilainya tidak boleh dikitar semula, maka ini akan menyebabkan kitaran hayat ThreadLocal ini menjadi seperti selagi benang ini (kerana rantai rujukan kukuh nilai ini selepas utas dilaksanakan akan terganggu), jika benang tidak pernah tamat dan nilai terkumpul tidak boleh dikitar semula, maka masalah kebocoran memori akan berlaku
The cara untuk menyelesaikan masalah di sini ialah: panggil ThreadLocal setiap kali selepas menggunakannya Kaedah remove() mengosongkan data
public void remove() { ThreadLocalMap m = getMap(Thread.currentThread()); if (m != null) m.remove(this); }
Di sini kita melihat perbezaan antara kunci sebagai rujukan yang kuat dan rujukan yang lemah
Jika kunci digunakan sebagai rujukan yang kuat, kitaran hayatnya adalah sepanjang benang, dan terdapat rantai rujukan yang stabil Tidak boleh dikitar semula, menyebabkan kebocoran memori Jika ia digunakan sebagai rujukan yang lemah, GC akan secara automatik mengitar semulanya dan nilainya boleh dikitar semula dengan lebih baik dalam kaedah remove() seterusnya, jadi kami biasanya menggunakan ThreadLocal Designed untuk menjadi statik peribadi, gunakan kaedah remove() untuk memadamnya secara manual selepas digunakan
Atas ialah kandungan terperinci Apakah prinsip pelaksanaan pembolehubah benang ThreadLocal di Jawa. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!