Diagram Status Thread
Thread termasuk 5 negara berikut.
1. Status Baru: Setelah objek utas dibuat, ia memasuki keadaan baru. Misalnya, utas utas = utas baru ().
2. Ready State (runnable): Juga dikenal sebagai "negara yang dapat dieksekusi". Setelah objek utas dibuat, utas lain memanggil metode start () objek untuk memulai utas. Misalnya, thread.start (). Sebuah utas dalam keadaan siap dapat dijadwalkan untuk dieksekusi oleh CPU kapan saja.
3. Running State (Running): Utas memperoleh izin CPU untuk dieksekusi. Perlu dicatat bahwa utas hanya dapat memasuki keadaan berjalan dari keadaan siap.
4. Status yang diblokir: Keadaan yang diblokir berarti bahwa utas tersebut menyerahkan hak penggunaan CPU untuk beberapa alasan dan sementara berhenti berjalan. Tidak sampai utas memasuki keadaan siap, ia memiliki kesempatan untuk pergi ke keadaan berjalan. Ada tiga jenis penyumbatan:
(01) Menunggu untuk memblokir - dengan memanggil metode wait's wait (), biarkan utas menunggu untuk menyelesaikan pekerjaan tertentu.
(02) Pemblokiran yang disinkronkan-Sebuah utas gagal untuk memperoleh kunci sinkronisasi yang disinkronkan (karena kunci ditempati oleh utas lain), itu akan memasuki keadaan pemblokiran yang disinkronkan.
(03) Pemblokiran lainnya-utas akan memasukkan status pemblokiran dengan menelepon tidur () atau bergabung () dari utas atau mengeluarkan permintaan I/O. Ketika status tidur () diatur waktu, bergabung () menunggu utas untuk diakhiri atau diatur waktunya, atau pemrosesan I/O selesai, utas yang dimasukkan kembali ke keadaan siap.
5. Status Mati: Utas telah selesai mengeksekusi atau keluar dari metode run () karena pengecualian, dan utas mengakhiri siklus hidupnya.
Menerapkan utas metode multi-threading dan runnable
Thread: Mewariskan kelas utas, mengimplementasikan metode run, dan panggil metode start di fungsi utama untuk memulai utas
RUNNABLE: Antarmuka, mengimplementasikan antarmuka yang dapat dijalankan, meneruskannya sebagai parameter ke konstruktor utas, dan memanggil metode start di main
contoh:
kelas tugas mengimplementasikan runnable {private int ticket = 10; @Override public void run () {for (int i = 0; i <20; i ++) {if (this.ticket> 0) {System.out.println (thread.currentThread (). GetName () + "Tiket dijual" + this.ticket--); }}}}}}; kelas publik runnableTest {public static void main (string [] args) {tugas myTask = new tugas (); Utas t1 = utas baru (myTask); Thread t2 = utas baru (myTask); Utas T3 = utas baru (myTask); t1.start (); t2.start (); t3.start (); }} // threadtest.java Kode Kode Sumber MyThread Extends Thread {Private Int Ticket = 10; public void run () {for (int i = 0; i <20; i ++) {if (this.ticket> 0) {System.out.println (this.getName () + "Tiket Jual: Tiket" + this.ticket--); }}}} kelas publik ThreadTest {public static void main (string [] args) {// Mulai 3 Threads T1, T2, T3; Setiap utas masing -masing menjual 10 tiket! Mythread t1 = mythread baru (); Mythread t2 = mythread baru (); Mythread t3 = mythread baru (); t1.start (); t2.start (); t3.start (); }};
Perbedaan antara utas dan runnable
Thread adalah kelas, dan Runnable adalah antarmuka; Thread sendiri adalah kelas yang mengimplementasikan antarmuka yang dapat dijalankan. Kita tahu bahwa "kelas hanya dapat memiliki satu kelas induk, tetapi dapat menerapkan banyak antarmuka", jadi runnable memiliki skalabilitas yang lebih baik. Selain itu, Runnable juga dapat digunakan untuk "berbagi sumber daya". Artinya, beberapa utas dibuat berdasarkan objek runnable tertentu, dan mereka akan berbagi sumber daya pada objek yang dapat dilalui. Secara umum, disarankan untuk menerapkan multi-threading melalui "runnable"!
Thread sudah dijalankan dan mulai
start (): fungsinya adalah untuk memulai utas baru, dan utas baru akan menjalankan metode run () yang sesuai. start () tidak dapat dipanggil berulang kali. start () sebenarnya memulai utas melalui metode lokal start0 (). start0 () akan menjalankan utas baru, dan utas baru akan memanggil metode run ().
run (): run () dapat disebut berulang kali seperti metode anggota biasa. Jika Anda menelepon run () secara terpisah, run () akan dieksekusi di utas saat ini, dan utas baru tidak akan dimulai! run () adalah secara langsung memanggil metode run () dari anggota runnable utas utas, dan tidak akan membuat utas baru.
// kelas kode sumber demo.java MyThread memperluas utas {public mythread (nama string) {super (name); } public void run () {System.out.println (thread.currentThread (). getName ()+"sedang berjalan"); }}; Demo kelas publik {public static void main (string [] args) {thread mythread = new mythread ("mythread"); System.out.println (thread.currentThread (). GetName ()+"hubungi mythread.run ()"); mythread.run (); System.out.println (thread.currentThread (). GetName ()+"Call MyThread.Start ()"); mythread.start (); }}Keluaran:
panggilan utama mythread.run () Main runningmain call mythread.start () mythread sedang berjalan
disinkronkan
Di Java, setiap objek memiliki kunci sinkronisasi. Ketika kita menyebut metode yang disinkronkan objek, kunci objek diperoleh, dan disinkronkan (OBJ) memperoleh kunci sinkronisasi "objek OBJ". Akses utas yang berbeda ke kunci sinkronisasi saling eksklusif. Kunci sinkronisasi objek hanya dapat diperoleh oleh satu utas pada waktu tertentu. Melalui kunci sinkronisasi, kita dapat mencapai akses yang saling eksklusif ke "objek/metode" di banyak utas. Misalnya, sekarang ada dua utas A dan Thread B, yang semuanya akan mengakses "kunci objek OBJ yang disinkronkan". Misalkan pada titik tertentu, encer A memperoleh "kunci sinkronisasi OBJ" dan melakukan beberapa operasi; Pada saat ini, Thread B juga mencoba untuk mendapatkan "kunci sinkronisasi OBJ" - Thread B akan gagal untuk memperoleh, ia harus menunggu sampai utas A melepaskan "kunci sinkronisasi OBJ" dan hanya dapat dijalankan.
Aturan Dasar
Pasal 1: Ketika utas mengakses "metode yang disinkronkan" atau "blok kode yang disinkronkan" dari "objek tertentu", utas lain akan diblokir dari akses ke "metode sinkronisasi" atau "blok kode yang disinkronkan" dari "objek".
Pasal 2: Ketika utas mengakses "metode yang disinkronkan" atau "blok kode yang disinkronkan" dari "objek tertentu", utas lain masih dapat mengakses blok kode yang disinkronkan dari "objek ini".
Pasal 3: Ketika utas mengakses "metode yang disinkronkan" atau "blok kode yang disinkronkan" dari "objek tertentu", utas lain akan diblokir dari mengakses "metode sinkronisasi" lainnya atau "blok kode yang disinkronkan" dari "objek".
Metode yang disinkronkan
public disinkronkan void foo1 () {System.out.println ("Metode Sinkronisasi");} Kode Sinkronisasi Blok Public Void FOO2 () {disinkronkan (this) {System.out.println ("Metode Sinkronisasi"); }}Ini di blok kode yang disinkronkan mengacu pada objek saat ini. Ini juga dapat diganti dengan objek lain, seperti ini diganti dengan OBJ, kemudian FOO2 () memperoleh kunci sinkronisasi OBJ ketika disinkronkan (OBJ).
Blok kode yang disinkronkan dapat mengontrol area akses yang dibatasi konflik dengan lebih akurat, dan terkadang berkinerja lebih efisien
Kunci instan dan kunci global
Instance terkunci pada objek instan. Jika kelas adalah singleton, maka kunci juga memiliki konsep kunci global. Kata kunci yang disinkronkan sesuai dengan kunci instance.
Global Lock-- Kunci ini ditargetkan di kelas. Tidak peduli berapa banyak objek contohnya, utas berbagi kunci. Kunci global sesuai dengan sinkronisasi statis (atau terkunci pada kelas atau objek ClassLoader dari kelas ini).
Kelas PULBIC Sesuatu {public disinkronkan void issynca () {} public disinkronkan void issyncb () {} public static static void csynca () {} public static void csyncB () {}} public static static void csyncb () {}} public static static void csyncb ()
(01) x.issynca () dan x.issyncb () tidak dapat diakses secara bersamaan. Karena issynca () dan issyncb () keduanya kunci sinkronisasi yang mengakses objek yang sama (objek X)!
(02) x.issynca () dan y.issynca () dapat diakses secara bersamaan. Karena tidak mengakses kunci sinkronisasi dari objek yang sama, x.issynca () mengakses kunci sinkronisasi X, sementara y.issynca () mengakses kunci sinkronisasi Y.
(03) x.csynca () dan y.csyncb () tidak dapat diakses secara bersamaan. Karena csynca () dan csyncb () keduanya tipe statis, x.csynca () setara dengan sesuatu.
(04) x.issynca () dan sesuatu.csynca () dapat diakses secara bersamaan. Karena issynca () adalah metode instan, x.issynca () menggunakan kunci objek X; Sementara csynca () adalah metode statis, sesuatu.csynca () dapat memahami bahwa itu adalah "kunci kelas" yang digunakan. Karena itu, mereka dapat diakses secara bersamaan.
Pemblokiran utas dan bangun tunggu, beri tahu, beri tahu Allah
Di objek.java, antarmuka seperti tunggu (), notify () dan notifyAll () didefinisikan. Fungsi tunggu () adalah membiarkan utas saat ini memasukkan status menunggu, dan tunggu () juga akan membiarkan utas saat ini melepaskan kunci yang dipegangnya. Peran notify () dan notifyall () adalah untuk membangunkan utas menunggu pada objek saat ini; Notify () adalah membangunkan satu utas, sementara notifyall () adalah membangunkan semua utas.
Detail API tentang menunggu/bangun di kelas objek adalah sebagai berikut:
Notify () - Bangun satu utas yang menunggu di monitor objek ini.
NotifyAll () - Bangun semua utas menunggu di monitor objek ini.
tunggu () - Letakkan utas saat ini dalam keadaan "Tunggu (pemblokiran)" dan "sampai utas lain memanggil metode notify () atau metode notifyall () dari objek ini", dan utas saat ini dibangunkan (dimasukkan ke "status siap").
Tunggu (jual lama) - Masukkan utas saat ini dalam keadaan "Tunggu (memblokir)" dan "sampai utas lain menyebut metode pemberitahuan objek () atau metode notifyall (), atau melebihi jumlah waktu yang ditentukan", dan utas saat ini dibangunkan (dimasukkan ke "status siap").
Tunggu (waktu lama, int nanos) - Biarkan utas saat ini berada dalam keadaan "tunggu (pemblokiran)", "sampai utas lain menyebut metode objek memberi tahu () metode atau notifyall (), atau beberapa utas lainnya mengganggu utas saat ini, atau telah melampaui jumlah waktu tertentu", dan utas saat ini dibangunkan (masuk ke "status siap").
// Waittest.java's Source Code Class Threada Extends Thread {public threada (name string) {super (name); } public void run () {disinkronkan (this) {System.out.println (thread.currentThread (). getName ()+"call notify ()"); // bangunkan utas tunggu saat ini notify (); }}} kelas publik waittest {public static void main (string [] args) {threada t1 = new threada ("t1"); disinkronkan (t1) {coba {// mulai "thread t1" system.out.println (thread.currentThread (). getName ()+"start t1"); t1.start (); // Utas utama menunggu T1 bangun melalui notify (). System.out.println (thread.currentThread (). GetName ()+"tunggu ()"); t1.Wait (); System.out.println (thread.currentThread (). GetName ()+"lanjutkan"); } catch (InterruptedException e) {E.PrintStackTrace (); }}}}Keluaran
start utama t1main tunggu () T1 call notify () Main Lanjutkan
(01) Perhatikan bahwa "utas utama" pada gambar mewakili "utas utama utama". "Thread T1" mewakili "Thread T1" dimulai di Waittest. Dan "kunci" mewakili "kunci sinkron dari objek T1".
(02) "Thread Utama" membuat "Thread T1" baru melalui Threada baru ("T1"). Kemudian, "kunci sinkron dari objek T1" diperoleh melalui sinkronisasi (T1). Kemudian hubungi t1.start () untuk memulai "Thread T1".
(03) "Thread Utama" mengeksekusi t1.wait () untuk melepaskan "kunci objek T1" dan memasuki "status tunggu (pemblokiran)". Tunggu utas pada objek T1 untuk membangunkannya melalui notify () atau notifyall ().
(04) Setelah "Thread T1" dijalankan, "kunci objek saat ini" diperoleh melalui sinkronisasi (ini); Kemudian hubungi notify () untuk membangunkan "utas menunggu pada objek saat ini", yaitu, bangunkan "utas utama".
(05) Setelah "Thread T1" selesai, lepaskan "kunci objek saat ini". Segera setelah itu, "utas utama" memperoleh "kunci objek T1" dan kemudian berjalan.
T1.Wait () adalah metode tunggu () yang dipanggil melalui "Thread T1", tetapi tempat di mana t1.wait () disebut ada di "utas utama utama". Utas utama haruslah "utas saat ini", yaitu keadaan berjalan, sebelum t1.wait () dapat dieksekusi. Oleh karena itu, "utas saat ini" saat ini adalah "utas utama utama"! Oleh karena itu, t1.wait () adalah untuk membuat "utas utama" tunggu, bukan "utas T1"!
Paket Thread.test; kelas publik notifyalltest {private static objek obj = objek baru (); public static void main (string [] args) {threada t1 = new threada ("t1"); Threada t2 = threada baru ("t2"); Threada t3 = threada baru ("t3"); t1.start (); t2.start (); t3.start (); coba {System.out.println (thread.currentThread (). getName ()+"sleep (3000)"); Thread.sleep (3000); } catch (InterruptedException e) {E.PrintStackTrace (); } disinkronkan (obj) {System.out.println (thread.currentThread (). getName ()+"notifyall ()"); obj.notifyall (); // bangun t1.t2.t3 di sini}} kelas statis threada memperluas thread {public threada (nama string) {super (name); } public void run () {disinkronkan (obj) {coba {// cetak hasil sistem.out.println (thread.currentThread (). getName () + "tunggu"); // Lepaskan Obj Object Lock Obj.wait (); // cetak hasil sistem.out.println (thread.currentThread (). GetName () + "lanjutkan"); } catch (InterruptedException e) {E.PrintStackTrace (); }}}}}} Keluaran:
T1 WaitMain Sleep (3000) T3 Waitt2 WaitMain NotifyAll () T2 Lanjutan3 Lanjutkan1 Lanjutkan
(01) 3 Thread "T1", "T2" dan "T3" dibuat dan dimulai di utas utama.
(02) Benang utama tidur selama 3 detik melalui tidur (3000). Selama utas utama tidur selama 3 detik, kami berasumsi bahwa tiga utas "T1", "T2" dan "T3" semuanya berjalan. Ambil "T1" sebagai contoh. Ketika berjalan, itu akan mengeksekusi obj.wait () untuk menunggu utas lain untuk membangunkannya melalui notify () atau nofityAll (); Dengan cara yang sama, "T2" dan "T3" juga akan menunggu utas lain untuk membangunkannya melalui nofity () atau nofityAll ().
(03) Benang utama tidur selama 3 detik dan kemudian berjalan. Jalankan obj.notifyall () untuk membangunkan utas menunggu di OBJ, yaitu, bangunkan tiga utas "t1", "t2" dan "t3". Segera setelah utas utama disinkronkan (OBJ) dijalankan, utas utama melepaskan "OBJ Lock". Dengan cara ini, "T1", "T2" dan "T3" dapat memperoleh "Obj Lock" dan terus berjalan!
Beri tahu, beri tahu dan mengunci hubungan
Fungsi seperti tunggu (), notify () di objek, seperti disinkronkan, akan beroperasi pada "kunci sinkronisasi objek".
tunggu () akan membuat "utas saat ini" tunggu. Karena utas memasuki keadaan menunggu, utas harus melepaskan "kunci sinkron" yang dipegang oleh kuncinya, jika tidak, utas lain tidak akan dapat memperoleh "kunci sinkron" dan tidak akan dapat berjalan!
OK, setelah utas panggilan tunggu (), itu akan melepaskan "kunci sinkron" yang dipegang oleh kuncinya; Dan, menurut pengantar sebelumnya, kita tahu bahwa utas penantian dapat dibangunkan dengan notify () atau notifyall (). Sekarang, tolong pikirkan tentang pertanyaan: apa yang diberitahukan () berdasarkan kebangkitan utas menunggu? Atau, apa korelasi antara tunggu () dan notify ()? Jawabannya adalah: berdasarkan "kunci sinkronisasi objek".
Utas yang bertanggung jawab untuk membangunkan utas menunggu (kami menyebutnya "Bangun utas"), hanya dapat membangunkan utas menunggu setelah mendapatkan "kunci sinkron dari objek ini" (kunci sinkronisasi di sini harus sama dengan kunci sinkronisasi dari utas yang menunggu) dan memanggil metode pemberitahuan () atau notifyall (). Meskipun, utas menunggu dibangunkan; Namun, itu tidak dapat dieksekusi segera karena utas bangun masih memegang "kunci sinkron untuk objek". Anda harus menunggu sampai utas bangun merilis "kunci sinkronisasi objek" sebelum Anda dapat memperoleh "kunci sinkronisasi objek" dan terus berjalan.
Singkatnya, beri tahu (), tunggu () bergantung pada "kunci sinkron", yang dipegang oleh kunci objek, dan setiap objek memiliki dan hanya satu! Inilah sebabnya mengapa fungsi seperti notify (), wait () didefinisikan di kelas objek, bukan di kelas utas.
Hasil konsesi utas
Konsesi utas membuat utas berubah dari status eksekusi ke keadaan siap, sehingga utas menunggu lainnya dengan prioritas yang sama dapat memperoleh hak eksekusi; Namun, tidak dijamin bahwa setelah hasil panggilan utas saat ini (), utas lain dengan prioritas yang sama pasti akan mendapatkan hak eksekusi; Mungkin juga bahwa utas saat ini memasuki "keadaan berjalan" dan terus berjalan.
Hasil dan tunggu
(01) tunggu () adalah membiarkan utas memasukkan status "tunggu (pemblokiran)" dari "status berjalan", sementara tidak menghasilkan () adalah membiarkan utas memasuki "status siap" dari "status berjalan".
(02) tunggu () adalah kunci sinkronisasi yang akan melepas objek yang dipegangnya, sedangkan metode hasil () tidak akan melepaskan kunci.
(03) Tunggu adalah metode objek, hasil adalah metode utas
Sleep Thread
Fungsi tidur () adalah membiarkan utas saat ini tidur, yaitu utas saat ini akan masuk dari "status berjalan" ke "status tidur (pemblokiran)". sleep () akan menentukan waktu tidur, dan waktu tidur utas akan lebih besar dari/sama dengan waktu tidur; Ketika utas dibangunkan lagi, itu akan berubah dari "status pemblokiran" menjadi "keadaan siap", menunggu CPU dijadwalkan untuk dieksekusi.
Perbedaan antara tidur dan tunggu
Fungsi tunggu () adalah untuk memungkinkan utas saat ini memasuki keadaan "Tunggu (memblokir) dari" status berjalan "dan juga melepaskan kunci sinkronisasi. Fungsi tidur () adalah membiarkan utas saat ini memasuki keadaan" Tidur (pemblokiran) dari "status berjalan". (Ini sebenarnya tidak jauh berbeda)
tunggu () melepaskan kunci sinkronisasi objek, sementara tidur () tidak melepaskan kunci
Tunggu adalah metode objek, tidur adalah metode utas
Bergabung
Biarkan utas utama menunggu, dan utas anak dapat terus berjalan setelah utas utama selesai.
mengganggu
Digunakan untuk mengakhiri utas yang diblokir
@Overridepublic void run () {coba {while (true) {// Jalankan tugas ...}} catch (interruptedException yaitu) {// karena pengecualian ExtraySception, keluar dari loop while (true) dan utas diakhiri! }}Dalam sementara (benar), panggilan untuk mengganggu () dari utas menghasilkan interupsi interupsi. Penangkapan yang terputus ada di luar sementara (benar), sehingga keluar dari loop sementara (benar)
Mengakhiri utas dalam keadaan berjalan
@OverridEpublic void run () {while (! IsInterrupted ()) {// Jalankan tugas ...}}Cara Umum Untuk Menghentikan Benang
@Overridepublic void run () {coba {// 1. IsInterrupted () menjamin bahwa utas akan diakhiri selama interupsi ditandai benar. while (! isInterrupted ()) {// Jalankan tugas ...}} catch (InterruptedException IE) {// 2. Pengecualian ExtrectedException menjamin bahwa ketika pengecualian Exception InterruptedException terjadi, utas diakhiri. }}
Prioritas utas
Kisaran prioritas utas di Java adalah 1 hingga 10, dan prioritas default adalah 5. "Benang prioritas tinggi" akan mendahului eksekusi daripada "utas prioritas rendah". Ada dua jenis utas di java: utas pengguna dan utas daemon. Mereka dapat dibedakan dengan metode isdaemon (): jika false dikembalikan, itu berarti bahwa utas adalah "utas pengguna"; Kalau tidak, itu adalah "benang daemon". Utas pengguna umumnya melakukan tugas tingkat pengguna, sedangkan utas daemon juga "utas backend", yang umumnya digunakan untuk melakukan tugas latar belakang. Perlu dicatat bahwa mesin virtual Java akan keluar setelah "utas pengguna" selesai.
Setiap utas memiliki prioritas. "Thread Prioritas Tinggi" akan mendahului eksekusi lebih dari "utas prioritas rendah". Setiap utas dapat ditandai sebagai daemon atau non-daemon. Saat membuat utas anak baru di beberapa utas utama yang berjalan, prioritas utas anak diatur untuk sama "prioritas utas utama yang membuatnya", dan "utas anak akan menjadi utas daemon" ketika dan hanya jika "utas utama yang membuatnya adalah utas daemon".
Ketika mesin virtual Java dimulai, biasanya ada satu utas non-daemon (utas ini dimulai melalui metode utama ()). JVM akan berjalan sampai salah satu dari kondisi berikut terjadi, dan JVM akan mengakhiri menjalankan:
(01) Metode keluar () dipanggil, dan keluar () memiliki izin untuk dieksekusi secara normal.
(02) Semua "utas non-daemon" mati (yaitu, hanya ada "benang daemon" di JVM).
Daemon
(01) Utas utama utama adalah utas pengguna, dan utas anak yang dibuatnya juga merupakan utas pengguna.
(02) T2 adalah benang daemon. Ketika "utas utama utama" dan "sub-thread T1" (keduanya adalah utas pengguna) dieksekusi dan hanya benang daemon yang tersisa, JVM secara otomatis keluar.
Masalah produsen dan konsumen
(01) Produser hanya memproduksi ketika gudang tidak penuh, dan menghentikan produksi ketika gudang penuh.
(02) Konsumen hanya dapat mengkonsumsi ketika mereka memiliki produk dalam penyimpanan, dan tunggu jika mereka memiliki gudang kosong.
(03) Ketika konsumen menemukan bahwa tidak ada produk untuk dikonsumsi di gudang, mereka akan memberi tahu produsen.
(04) Ketika produsen memproduksi produk yang dapat dikonsumsi, mereka harus memberi tahu konsumen yang menunggu untuk dikonsumsi.
Komunikasi antara utas
Metode: memori dan pesan bersama
Memori Bersama: Thread A dan Thread B Berbagi Memori, Thread A Memperbarui nilai variabel bersama, menyegarkannya ke memori utama, dan Thread B masuk ke memori utama untuk membaca variabel yang diperbarui dari Thread A. Seluruh proses komunikasi harus melewati memori utama. Sinkronisasi dilakukan secara eksplisit.
Jika suatu variabel adalah tipe volatil, baca dan tulis variabel akan bersifat atom. Jika beberapa operasi volatil atau operasi komposit yang mirip dengan volatile ++, operasi ini tidak atom secara keseluruhan.
Variabel volatil itu sendiri memiliki karakteristik berikut:
[Visibilitas]: Saat membaca variabel yang mudah menguap, Anda selalu dapat melihat tulisan terakhir ke variabel volatil (utas apa pun).
[Atomisitas]: Ini memiliki atomisitas untuk membaca/menulis variabel volatil tunggal, tetapi tidak memiliki atomisitas untuk operasi senyawa yang mirip dengan volatil ++.
Penulisan yang mudah menguap: Saat menulis variabel yang mudah menguap, JMM akan menyiram variabel bersama dalam memori lokal yang sesuai dengan utas ke memori utama.
Baca Volatile: Saat membaca variabel yang mudah menguap, JMM akan membatalkan memori lokal yang sesuai dengan utas. Utas selanjutnya akan membaca variabel bersama dari memori utama.
Pengiriman Pesan: Pengiriman pesan dilakukan secara implisit sebelum pesan diterima.
Threadlocal
Threadlocal tidak digunakan untuk memecahkan masalah akses multi-thread ke objek bersama. Secara umum, objek ke utas melalui threadlocal.set () adalah objek yang digunakan oleh utas itu sendiri. Utas lain tidak perlu diakses dan tidak dapat diakses. Threadlocal memungkinkan setiap utas untuk mempertahankan objek independennya sendiri. Ini tidak diimplementasikan melalui threadlocal.set (), tetapi objek yang dibuat oleh pengoperasian objek baru di setiap utas. Setiap utas membuat satu, bukan salinan atau salinan objek. Referensi ke objek yang baru dibuat disimpan ke peta masing -masing utas melalui threadlocal.set (). Setiap utas memiliki peta seperti itu. Ketika threadlocal.get () dieksekusi, setiap utas mengeluarkan objek yang ditempatkan dari peta sendiri. Oleh karena itu, apa yang diambil adalah objek di setiap utas. Instance Threadlocal digunakan sebagai kunci peta. Jika hal yang dimasukkan oleh threadlocal.set () adalah objek yang sama yang dibagikan oleh beberapa utas, maka threadlocal.get () dari beberapa utas masih memperoleh objek bersama itu sendiri, dan masih ada masalah akses bersamaan.
Implementasi threadlocal
impor java.util.collections; impor java.util.hashmap; impor java.util.map; /** * Kelas Menggunakan ThreadLocal * * @author leizhimin 2010-1-5 10:35:27 */kelas publik myThreadlocal {// tentukan variabel threadlocal untuk menyimpan int atau integer data private @lavaSoft.test2.threadlocal <integer> tl = com.lavasoft {new New.test2.Threadlocal <Integer> tl = com.lavasoft.test.test2.threadlocal <Integer> tl = com.lavasoft.toVasoft.ToVer.ToVER.THERODLOCAL <Integer> tl = com.lavasoft.toVasoft.toVer.ToVer.Theadlocal <Integer> tl = com.lavasoft.lavasoft.toVer. 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 (); }} 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 ()); }}Faktanya, Threadlocal melakukan ini:
public t get () {thread t = thread.currentThread (); ThreadLocalMap Map = getMap (t); if (peta! = null) {threadlocalmap.entry e = map.getEntry (this); if (e! = null) return (t) e.value; } return setInitialValue (); }