Masih ada perbedaan antara variabel anggota threadlocal dan thread. Kelas Threadlocal menyediakan variabel lokal utas. Variabel lokal ini berbeda dari variabel anggota umum. Ketika variabel utas digunakan oleh beberapa utas, setiap utas hanya bisa mendapatkan satu salinan variabel. Ini adalah deskripsi di Java API. Dengan membaca kode sumber API, saya menemukan bahwa itu bukan salinannya. Apa konsep salinannya? Klon? Atau sesuatu yang lain, terlalu kabur.
Lebih tepatnya, registri (peta <thread, t>) di dalam variabel tipe threadlocal telah berubah, tetapi variabel tipe threadlocal itu sendiri memang satu, dan ini adalah esensi!
Inilah contohnya:
1. Contoh standar
Kelas mythreadlocal didefinisikan, dan objeknya dibuat, dan digunakan oleh empat utas. Akibatnya, variabel TLT dari empat utas tidak berbagi. Yang kedua adalah menggunakannya sendiri, yang menunjukkan bahwa keempat utas menggunakan salinan TLT (klon).
/*** Gunakan kelas threadlocal*/kelas publik myThreadlocal {// tentukan variabel threadlocal untuk menyimpan int atau integer data private threadlocal <integer> tl = threadlocal baru <integer> () {@override dilindungi inisi inisial integer () {return 0; }}; Integer publik getNextNum () {// Dapatkan nilai TL dan tambahkan 1, dan perbarui nilai T1 tl.set (tl.get () + 1); return tl.get (); }} / *** Uji utas*/ kelas publik testThread memperluas utas {private mythreadlocal tlt = myThreadlocal baru (); testThread publik (mythreadlocal tlt) {this.tlt = tlt; } @Override public void run () {for (int i = 0; i <3; i ++) {System.out.println (thread.currentThread (). GetName () + "/t" + tlt.getNextNum ()); }}} / *** Tes ThreadLocal*/ Tes Kelas Publik {public static void main (string [] args) {myThreadlocal tlt = new myThreadlocal (); Thread t1 = testThread baru (TLT); Thread t2 = testThread baru (TLT); Thread t3 = testThread baru (TLT); Thread t4 = testthread baru (tlt); t1.start (); t2.start (); t3.start (); t4.start (); }}
Dapat dilihat bahwa ketiga utas tersebut diberi nomor secara mandiri dan tidak saling mempengaruhi:
Thread-0 1 Thread-1 1 Thread-0 2 Thread-1 2 Thread-0 3 Thread-1 3 Thread-2 1 Thread-3 1 Thread-2 2 Thread-3 2 Thread-2 3 Thread-3 Proses Selesai Dengan Kode Keluar 0
Objek TLT adalah satu, dan objek TL omong kosong juga satu, karena hubungan kombinasi adalah satu-ke-satu. Namun, dengan jumlah utas meningkat, banyak objek integer akan dibuat. Hanya bilangan bulat dan int sudah umum. Jadi saya tidak bisa merasakan sifat objek Integer.
2. Jangan gunakan threadlocal
Jika Anda tidak menggunakan ThreadLocal, Anda hanya perlu mendefinisikan kembali kelas MyThreadlocal sebagai:
/ *** Gunakan kelas threadlocal*/ kelas publik mythreadlocal {private integer t1 = 0; integer publik getNextNum () {return t1 = t1+1; } // Tentukan variabel threadlocal untuk menyimpan data int atau integer // threadlocal pribadi <Integer> tl = threadlocal baru <integer> () {// @override // Integer initialValue () {// return 0; //} //}; // // Integer publik getNextNum () {// // Dapatkan nilai TL dan tambahkan 1, dan perbarui nilai t1 // tl.set (tl.get () + 1); // return tl.get (); //}}
Kemudian jalankan tes:
Thread-2 1 Thread-2 2 Thread-1 Thread-1 Thread-6 Thread-3 3 Thread-3 9 Thread-3 10 Thread-1 8 Thread-0 7 Thread-0 11 Thread-0 12 Thread-2 5 Proses Selesai Dengan Kode Keluar 0
Dari sini, kita dapat melihat bahwa keempat utas berbagi variabel TLT, dan setiap utas secara langsung memodifikasi properti TLT.
3. Realisasi Threadlocal sendiri
paket com.lavasoft.test2; impor java.util.collections; impor java.util.hashmap; impor java.util.map; /*** Gunakan kelas threadlocal*/kelas publik myThreadlocal {// tentukan variabel threadlocal untuk menyimpan int atau integer data private com.lavasoft.test2.threadlocal <Integer> tl = com.lavasoft.test2.threadlocal <Integer> () {@Override Protect.test2.threadlocal (Integer> () {) @Override; }}; Integer publik getNextNum () {// Dapatkan nilai TL dan tambahkan 1, dan perbarui nilai T1 tl.set (tl.get () + 1); return tl.get (); }} class ThreadLocal <T> {private Map <thread, t> peta = collections.synchronizedMap (hashmap baru <thread, t> ()); Public ThreadLocal () {} Protected t initialValue () {return null; } public t get () {thread t = thread.currentThread (); T obj = map.get (t); if (obj == null &&! map.containskey (t)) {obj = initialValue (); peta.put (t, obj); } kembalikan obj; } public void set (nilai t) {map.put (thread.currentThread (), value); } public void remeF () {map.remove (thread.currentThread ()); }}
Jalankan tes:
Thread-0 1 Thread-0 2 Thread-0 3 Thread-2 1 Thread-2 2 Thread-3 1 Thread-2 3 Thread-3 2 Thread-1 Thread-3 3 Thread-1 2 Thread-1 Proses Selesai Dengan Kode Keluar 0
Anehnya, versi peniru dari ThreadLocal ini juga bekerja dengan baik, menerapkan fungsi ThreadLocal di Java API.
4. Lihat esensi melalui fenomena
Bahkan, dari perspektif program, variabel TLT memang satu, tanpa keraguan. Tetapi mengapa nomor yang dicetak tidak saling mempengaruhi?
Apakah karena menggunakan Integer? -----TIDAK.
Alasannya adalah: T yang Dilindungi TinitialValue () dan get (), karena ketika setiap utas memanggil (), itu akan membuatnya jika tidak ada di peta. Ketika disebut, variabel baru dibuat dengan Type T. Setiap kali mereka baru dibuat, tentu saja, masing -masing menggunakannya tanpa efek satu sama lain.
Untuk melihat esensi dengan jelas, ganti integer dan tulis ulang beberapa kelas:
paket com.lavasoft.test2; impor java.util.collections; impor java.util.hashmap; impor java.util.map; /*** Gunakan kelas threadlocal*/kelas publik mythreadlocal {// tentukan variabel threadlocal untuk menyimpan int integer data // threadlocal pribadi <bean> tl = threadlocal baru <bean> () {private com.lavasoft.test2.threadlocal <bean> tl = new com.lavaSoft.test2.threadlocal <bean> tl = new com.lavaSoft.test2.theadlocal <bean> tl = new com.lavaSoft.test2 @Override Protected Bean InitialValue () {return new bean (); }}; @Override public string toString () {return "mythreadlocal {" + "tl =" + tl + '}'; } public bean getBean () {return tl.get (); }} class ThreadLocal <T> {private Map <thread, t> peta = collections.synchronizedMap (hashmap baru <thread, t> ()); Public ThreadLocal () {} Protected t initialValue () {return null; } public t get () {thread t = thread.currentThread (); T obj = map.get (t); if (obj == null &&! map.containskey (t)) {obj = initialValue (); peta.put (t, obj); } kembalikan obj; } public void set (nilai t) {map.put (thread.currentThread (), value); } public void remeF () {map.remove (thread.currentThread ()); }} paket com.lavasoft.test2; / ** * uji kacang */ Kelas publik bean {private string id = "0"; name string pribadi = "tidak ada"; bean publik () {} bean publik (id string, nama string) {this.id = id; this.name = name; } public String getId () {return id; } public void setId (string id) {this.id = id; } public string getName () {return name; } public void setName (name string) {this.name = name; } public String showInfo () {return "bean {" + "id = '" + id +'/'' + ", name = '" + name +'/'' + '}'; }} paket com.lavasoft.test2; / *** Uji utas*/ kelas publik testThread memperluas utas {private mythreadlocal tlt = myThreadlocal baru (); testThread publik (mythreadlocal tlt) {this.tlt = tlt; } @Override public void run () {System.out.println (">>>>:" + tlt); untuk (int i = 0; i <3; i ++) {System.out.println (thread.currentThread (). getName ()+"/t"+tlt.getBean ()+"/t"+tlt.getBean (). ShowInfo ()); }}}
Kemudian jalankan tes:
>>>>>: mythreadlocal {tl=com.lavasoft.test2.mythreadlocal$1@1de3f2d} >>>>>: mythreadlocal {tl=com.lavasoft.test2.mythreadlocal$1@1de3f2d} >>>>>: myThreadlocal {tl=com.lavasoft.test2.bean@291aff bean {id = '0', name = 'none'} thread-2 com.lavasoft.test2.bean@fe64b9 bean {id = '0', name = 'none'} thread-3 com.lava.lavas. Bean {id = '0', name = 'none'} thread-2 com.lavasoft.test2.bean@fe64b9 bean {id = '0', name = 'none'} thread-2 com.lavasoft.test2.bean@fe64b9 bean {id = '0', name = 'tidak ada. Bean {id = '0', name = 'none'} thread-0 com.lavasoft.test2.bean@291aff bean {id = '0', name = 'none'} thread-3 com.lavasoft.test2.bean@186db54 bean {id = '0', name = 'noing' Bean {id = '0', name = 'none'} thread-1 com.lavasoft.test2.bean@291aff bean {id = '0', name = 'none'} thread-0 com.lavasoft.test2.bean@291aff bean {id = '0', name = 'none'} thread-0 com.0 Bean {id = '0', name = 'none'} thread-1 com.lavasoft.test2.bean@291aff bean {id = '0', name = 'none'} proses selesai dengan kode keluar 0
Jelas dari hasil pencetakan bahwa objek TLT MyThreadlocal memang satu, dan objek TL threadlocal dalam objek TLT juga satu. Namun, ketika T1T digunakan untuk setiap utas, utas akan membuat ulang objek kacang dan menambahkannya ke peta benang untuk digunakan.
Beberapa Kesalahpahaman Tentang Threadlocal:
1. Threadlocal adalah implementasi benang java
Threadlocal memang terkait dengan utas Java, tetapi itu bukan implementasi utas Java, itu hanya digunakan untuk mempertahankan variabel lokal. Untuk setiap utas, ia menyediakan versi variabelnya sendiri, terutama untuk menghindari konflik utas, dan setiap utas mempertahankan versinya sendiri. Independen satu sama lain, dan modifikasi tidak akan saling mempengaruhi.
2. Threadlocal relatif untuk setiap sesi
Threadlocal, sesuai namanya, ditujukan untuk utas. Dalam pemrograman web Java, setiap pengguna memiliki pengidentifikasi sesi sendiri dari awal hingga akhir sesi. Tapi Threadlocal tidak ada di lapisan sesi. Faktanya, Threadlocal tidak tergantung pada sesi pengguna. Ini adalah perilaku sisi server. Setiap kali server menghasilkan utas baru, ia memelihara utasnya sendiri.
Mengenai kesalahpahaman ini, saya pribadi percaya bahwa itu harus menjadi hasil dari tes lokal pengembang berdasarkan beberapa server aplikasi. Seperti yang kita semua tahu, server aplikasi umum memelihara satu set kumpulan benang, yaitu, untuk setiap akses, utas baru tidak harus menghasilkan. Sebaliknya, saya memiliki kumpulan cache benang. Untuk akses, pertama temukan utas yang ada dari kumpulan cache. Jika mereka telah menggunakan semua, maka utas baru akan dihasilkan.
Oleh karena itu, karena pengembang biasanya satu -satunya yang menguji dirinya sendiri, beban server sangat kecil, yang mengarah pada berbagi utas yang sama setiap kali aksesnya, menghasilkan kesalahpahaman: setiap sesi memiliki threadlocal
3. Threadlocal relatif untuk setiap utas. Setiap kali pengguna mengakses, akan ada threadlocal baru.
Secara teoritis, threadlocal memang relatif terhadap masing -masing utas, setiap utas akan memiliki threadlocal sendiri. Tetapi seperti yang disebutkan di atas, server aplikasi umum memelihara satu set kumpulan benang. Oleh karena itu, pengguna yang berbeda dapat menerima utas yang sama. Oleh karena itu, saat melakukan berbasis headlocal, Anda harus berhati-hati untuk menghindari cache variabel benang, menyebabkan utas lain mengakses variabel utas
4. Untuk setiap akses pengguna, ThreadLocal dapat digunakan beberapa kali.
Dapat dikatakan bahwa Threadlocal adalah pedang bermata dua, dan dapat memiliki hasil yang sangat baik jika digunakan. Namun, jika threadlocal tidak digunakan dengan baik, itu akan sama dengan variabel global. Kode tidak dapat digunakan kembali dan tidak dapat diuji secara mandiri. Karena beberapa kelas yang bisa digunakan kembali sekarang mengandalkan variabel utas. Jika tidak ada threadlocal, kelas -kelas ini menjadi tidak tersedia. Saya pribadi berpikir bahwa threadlocal digunakan dengan baik dan layak dirujuk
1. Simpan pengguna sesi saat ini: gempa ingin jert
2. Simpan beberapa variabel konteks, seperti ActionContext Action WebWork
3. Sesi Store, seperti Sesi ORM Spring Hibernate