Rumah  >  Artikel  >  Java  >  Apakah prinsip pelaksanaan pembolehubah benang ThreadLocal di Jawa

Apakah prinsip pelaksanaan pembolehubah benang ThreadLocal di Jawa

PHPz
PHPzke hadapan
2023-05-16 21:07:10565semak imbas

Apakah itu ThreadLocal?

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:

Apakah prinsip pelaksanaan pembolehubah benang ThreadLocal di Jawa

Analisis prinsip pelaksanaan ThreadLocal

ThreadLocal ialah kelas generik yang boleh menerima sebarang jenis objek Ia mengekalkan kelas dalaman statik ThreadLocalMap. get(), set(), dsb. yang kami gunakan sebenarnya berasal dari kelas ini, dan ia akan menjadi The benang semasa mencipta objek ThreadLocalMap untuk merekodkan nilai peribadi

Apakah prinsip pelaksanaan pembolehubah benang ThreadLocal di Jawa

Mula-mula lihat kaedah 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);
}

dan kemudian kaedah 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 boleh difahami sebagai enkapsulasi ThreadLocalMap

Masalah kebocoran memori ThreadLocal

Dalam ThreadLocalMap, objek ThreadLocal menggunakan rujukan lemah sebagai kunci

Apakah prinsip pelaksanaan pembolehubah benang ThreadLocal di JawaDalam 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!

Kenyataan:
Artikel ini dikembalikan pada:yisu.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam