Di Spring Cloud, kami menggunakan Hystrix untuk mengimplementasikan pemutus sirkuit. Di Zuul, semaphores digunakan secara default (Hystrix diikat secara default). Kita dapat menggunakan isolasi utas melalui konfigurasi.
Saat menggunakan isolasi utas, ada masalah yang harus diselesaikan, yaitu, dalam beberapa skenario bisnis, data dilewatkan dalam utas melalui threadlocal. Tidak apa -apa menggunakan semaphores, dan itu datang dari permintaan, tetapi proses selanjutnya adalah tentang satu utas.
Ketika mode isolasi berulir, Hystrix akan memasukkan permintaan ke kumpulan utas Hystrix untuk dieksekusi. Pada saat ini, permintaan akan menjadi utas B, dan Threadlocal pasti akan hilang.
Mari kita simulasikan proses ini melalui kolom sederhana:
kelas publik customthreadlocal {static threadlocal <string> threadlocal = new threadlocal <> (); public static void main (string [] args) {thread baru (runnable baru () {@Override public void run () {customThreadlocal.threadlocal.set ("apes"); layanan baru (). call ();}}). start (); }} Layanan kelas {public void call () {System.out.println ("Service:" + Thread.CurrentThread (). GetName ()); System.out.println ("Layanan:" + CustomThreadLocal.Threadlocal.get ()); DAO baru (). Call (); }} class dao {public void call () { System.out.println ("============================================================================================================================================================= =============================================================================================================================================== =============================================================================================================================================== ============================================================================================================================================= CustomThreadlocal.threadlocal.get ());Kami mendefinisikan threadlocal di kelas utama untuk melewati data, kemudian utas dibuat, dan metode panggilan dalam layanan dipanggil di utas, dan nilai diatur dalam threadlocal, dan nilai dalam threadlocal diperoleh dalam layanan, dan kemudian metode panggilan dalam DAO dipanggil, yang juga diperoleh di threadlocal. Mari kita jalankan untuk melihat efeknya:
Layanan: Thread-0
Layanan: Kera dan Surga
=====================================
DAO: Thread-0
Dao: Dunia Dunia
Anda dapat melihat bahwa seluruh proses dieksekusi di utas yang sama, dan nilai di Threadlocal telah diperoleh dengan benar. Tidak ada masalah dalam situasi ini.
Selanjutnya, kami mengubah program, melakukan switching utas, dan menelepon panggilan di DAO untuk memulai kembali eksekusi utas:
kelas publik customthreadlocal {static threadlocal <string> threadlocal = new threadlocal <> (); public static void main (string [] args) {thread baru (runnable baru () {@Override public void run () {customThreadlocal.threadlocal.set ("apes"); layanan baru (). call ();}}). start (); }} Layanan kelas {public void call () {System.out.println ("Service:" + Thread.CurrentThread (). GetName ()); System.out.println ("Layanan:" + CustomThreadLocal.Threadlocal.get ()); // DAO baru (). Call (); utas baru (runnable baru () {@Override public void run () {new dao (). call ();}}). start (); }} class dao {public void call () { System.out.println ("==================================================================================================================================================== ================================================================================================================================================================== =============================================================================================================================================== ================================================================================================================================================================== System.out.println ("Dao:" + Thread.CurrentThread (). GetName ());Jalankan lagi untuk melihat efeknya:
Layanan: Thread-0
Layanan: Kera dan Surga
=====================================
DAO: Thread-1
DAO: NULL
Anda dapat melihat bahwa permintaan ini diselesaikan oleh dua utas. Anda masih bisa mendapatkan nilai threadlocal dalam layanan. Anda tidak bisa mendapatkannya di DAO karena utas telah diaktifkan. Ini adalah masalah bahwa data Threadlocal akan hilang di awal.
Jadi bagaimana menyelesaikan masalah ini sebenarnya sangat sederhana, Anda hanya perlu mengubah satu baris kode:
threadlocal statis <string> threadlocal = new OheritableThreadlocal <> ();
Ubah Threadlocal menjadi warisanbetriadlokal, mari kita lihat efeknya setelah transformasi:
Layanan: Thread-0
Layanan: Kera dan Surga
=====================================
DAO: Thread-1
Dao: Dunia Dunia
Nilainya dapat diperoleh secara normal. DiwarisieTreadlocal disebabkan oleh pemecahan masalah bahwa Threadlocal tidak bisa mendapatkan nilainya karena switching utas ini.
Untuk memahami prinsip warisan yang dapat dipahami, kita harus terlebih dahulu memahami prinsip threadlocal. Mari kita perkenalkan secara singkat prinsip Threadlocal:
Setiap utas memiliki properti threadlocals tipe threadlocalmap. Kelas ThreadLocalMap setara dengan peta. Kuncinya adalah Threadlocal itu sendiri, dan nilainya adalah nilai yang kami tetapkan.
Thread kelas publik mengimplementasikan runnable {threadlocal.threadlocalmap threadLocals = null;} Ketika kami melewati threadlocal.set ("kera dan dunia");, kami menempatkan pasangan nilai kunci di properti threadlocals di utas ini. Kuncinya adalah utas saat ini, dan nilainya adalah nilai yang Anda atur.
public void set (nilai t) {thread t = thread.currentThread (); ThreadLocalMap Map = getMap (t); if (peta! = null) peta.set (ini, nilai); lain createMap (t, value);} Saat kami menggunakan metode threadlocal.get (), kami memperoleh nilai yang ditetapkan oleh utas ini berdasarkan utas saat ini sebagai kunci.
public t get () {thread t = thread.currentThread (); ThreadLocalMap Map = getMap (t); if (peta! = null) {threadlocalmap.entry e = map.getEntry (this); if (e! = null) {@suppresswarnings ("Uncecked") t result = (t) e.value; hasil pengembalian; }} return setInitialValue ();}Melalui pengantar di atas, kita dapat memahami bahwa threadlocal dapat meneruskan data dengan menggunakan thread.currentThread () untuk mendapatkannya, yaitu, asalkan di utas yang sama, nilai yang diatur di depan dapat diperoleh.
Jika operasi berikutnya menciptakan kembali utas setelah threadlocal telah menetapkan nilai, dan thread.currentThread () telah berubah saat ini, maka Anda pasti tidak akan mendapatkan nilai yang Anda tetapkan sebelumnya. Untuk reproduksi masalah tertentu, silakan merujuk ke kode saya di atas.
Lalu mengapa diwariskan dengan baik, oke?
Kelas yang diwariskan. Metode 3 metode. Saat membuat utas utas baru pada utas saat ini, variabel utas ini akan diteruskan dari utas saat ini ke instance utas baru.
Kelas publik diwarisieTreadlocal <T> memperluas threadlocal <T> { /** * menghitung nilai awal anak untuk variabel thread-lokal yang dapat diwariskan ini sebagai fungsi dari nilai orang tua pada saat utas anak * dibuat. Metode ini dipanggil dari dalam utas induk * sebelum anak dimulai. * <p> * Metode ini hanya mengembalikan argumen inputnya, dan harus diganti * jika perilaku yang berbeda diinginkan. * * @param ParentValue Nilai utas induk * @return Nilai awal utas anak */ dilindungi t childValue (t ParentValue) {return ParentValue; } /*** Dapatkan peta yang terkait dengan threadlocal. * * @param t utas saat ini */ threadlocalmap getMap (thread t) {return t.inHeriteItableThreadLocals; } /*** Buat peta yang terkait dengan threadlocal. * * @param t utas saat ini * @param FirstValue Nilai untuk entri awal tabel. */ void createMap (thread t, t firstValue) {t.inHeritableThreadlocals = new threadLocalMap (this, firstValue); }}Melalui kode di atas, kita dapat melihat bahwa diwarisieTreadlocal menulis ulang tiga metode nilai anak, getMap, dan createMap. Ketika kami menetapkan nilai di dalamnya, nilainya disimpan dalam warisan yang dapat diwariskan, alih -alih benang sebelumnya.
Poin kuncinya ada di sini. Mengapa kita bisa mendapatkan nilai di ThreadLocal di utas sebelumnya saat membuat kumpulan utas baru? Alasannya adalah bahwa ketika utas baru dibuat, warisan yang dapat diwariskan dengan utas sebelumnya akan ditugaskan ke warisan yang diwariskan.
Kode sumber awalnya dalam metode thread init, sebagai berikut:
if (parent.inheritableThreadlocals! = null) this.inHeritableThreadlocals = threadlocal.createinneritedMap (parent.inHeritableThreadlocals);
createInheritedMap sebagai berikut:
statis ThreadLocalMap createinitedMap (threadLocalMap ParentMap) {return new ThreadLocalMap (ParentMap); }Kode Penugasan:
threadlocalmap pribadi (threadLocalMap parentMap) {entri [] parenttable = parentMap.table; int len = parenttable.length; setThreshold (len); Tabel = entri baru [len]; untuk (int j = 0; j <len; j ++) {entri e = parenttable [j]; if (e! = null) {@suppressWarnings ("Uncecked") ThreadLocal <BOMPOCTE> key = (ThreadLocal <Peject>) e.get (); if (key! = null) {objek nilai = key.childvalue (e.value); Entri c = entri baru (kunci, nilai); int h = key.threadlocalhashcode & (len - 1); while (tabel [h]! = null) h = nextIndex (h, len); Tabel [h] = c; ukuran ++; }}}}Hingga saat ini, melalui warisan yang dapat diwariskan, kita dapat memberikan nilai dalam benang lokal ke utas anak ketika utas induk membuat utas anak. Fitur ini dapat memenuhi sebagian besar kebutuhan, tetapi ada masalah serius lain bahwa jika itu digunakan kembali, akan ada masalah. Misalnya, jika itu digunakan kembali, ia akan menggunakan whereitableThreadlocals di kumpulan utas untuk memberikan nilai, karena diwariskan dengan baik hanya akan memberikan nilai saat membuat utas baru. ThreadReuse tidak akan melakukan operasi ini. Jadi untuk menyelesaikan masalah ini, Anda harus memperluas kelas utas sendiri untuk mengimplementasikan fungsi ini.
Jangan lupa bahwa kami melakukan Java. Dunia open source memiliki semua yang Anda butuhkan. Di bawah ini saya merekomendasikan perpustakaan Java yang telah diimplementasikan, yang merupakan open source-thread-thread-local Alibaba.
Alamat GitHub: https://github.com/alibaba/transmittable-thread-local
Fungsi utama adalah untuk memecahkan masalah pengiriman nilai threadlocal saat menggunakan kumpulan utas dan komponen lain yang cache utas, dan menyelesaikan masalah pengiriman konteks selama eksekusi asinkron.
Kelas warisan JDK yang diwariskan dapat menyelesaikan nilai lewat utas induk ke utas anak. Namun, untuk kasus di mana kumpulan utas digunakan dan komponen lain yang cache utas, utas dibuat oleh kumpulan utas, dan utas di -cache dan digunakan berulang kali; Pada saat ini, tidak ada artinya untuk melewati nilai threadlocal dari hubungan benang orangtua-anak. Apa yang dibutuhkan aplikasi sebenarnya untuk melewati nilai threadlocal saat mengirimkan tugas ke kumpulan utas ke eksekusi tugas.
Metode penggunaan lokal yang dapat ditransmisikan dibagi menjadi tiga jenis: memodifikasi runnable dan callable, memodifikasi kumpulan utas, dan agen java untuk memodifikasi kelas implementasi kumpulan utas JDK
Selanjutnya, mari kita tunjukkan metode modifikasi kumpulan utas. Pertama, mari kita ambil kasus abnormal, kodenya adalah sebagai berikut:
kelas publik CustomThreadlocal {static ThreadLocal <String> threadlocal = new OheritableThreadlocal <> (); Static ExecutorService Pool = Executors.newfixedThreadPool (2); public static void main (string [] args) {for (int i = 0; i <100; i ++) {int j = i; pool.execute (utas baru (runnable baru () {@Override public void run () {customThreadlocal.threadlocal.set ("APE World"+j); layanan baru (). Call ();}})); }}} Layanan kelas {public void call () {customThreadlocal.pool.execute (runnable baru () {@Override public void run () {baru dao (). call ();}}); }} class dao {public void call () {System.out.println ("dao:" + customThreadlocal.threadlocal.get ()); }}Hasil menjalankan kode di atas salah, dan outputnya adalah sebagai berikut:
DAO: APE World 99
DAO: APE World 99
DAO: APE World 99
DAO: APE World 99
DAO: APE World 99
DAO: APE World 99
DAO: APE World 99
DAO: APE World 99
DAO: APE World 99
DAO: APE World 99
DAO: APE World 99
DAO: APE World 99
DAO: APE World 99
Yang benar harus dari 1 hingga 100. Karena penggunaan kembali utas, nilainya hanya akan diganti jika diganti.
Selanjutnya, gunakan yang dapat ditransmisikan-thread-local untuk mengubah kode bermasalah dan menambahkan ketergantungan Maven dari lokal yang dapat ditransmisikan:
<dependency> <GroupId> com.alibaba </groupid> <ArTifactId> transmitable-thread-local </artifactid> <version> 2.2.0 </version> </dependency>
Cukup modifikasi 2 tempat, ubah kumpulan utas dan ganti warisan yang dapat diwariskan:
statis transmittableThreadlocal <string> threadlocal = new TransmittableThreadlocal <> (); static executorservice pool = ttlexecutors.getttlexecutorservice (executors.newfixedThreadpool (2));
Hasil yang benar adalah sebagai berikut:
Dao: Ape World 85
Dao: Kera dan Dunia 84
Dao: Kera dan Dunia 86
Dao: Kera dan Dunia 87
Dao: Kera dan Dunia 88
DAO: APE World 90
Dao: Kera dan Dunia 89
DAO: APE World 91
DAO: APE World 93
Dao: Ape World 92
DAO: APE World 94
Dao: Ape World 95
DAO: APE World 97
DAO: APE World 96
DAO: APE World 98
DAO: APE World 99
Pada titik ini, kita dapat dengan sempurna menyelesaikan transmisi data benang dalam kumpulan benang. Pembaca yang budiman bingung lagi. Judulnya bukan tentang cara menyelesaikan masalah ini di Spring Cloud. Saya juga menemukan masalah ini di Zuul. Solusinya telah diceritakan kepada semua orang. Adapun bagaimana menyelesaikan masalah ini di Zuul, semua orang perlu memikirkannya sendiri. Saya akan membaginya dengan Anda jika Anda punya waktu nanti.
Di atas adalah semua konten artikel ini. Saya berharap ini akan membantu untuk pembelajaran semua orang dan saya harap semua orang akan lebih mendukung wulin.com.