Java Multithreading (satu)
Sebagai titik pengetahuan yang sangat penting di Java, masih perlu merangkumnya di sini.
1. Siklus hidup utas dan lima status dasar
Mengenai siklus hidup utas di java, mari kita lihat gambar klasik berikut:
Angka di atas pada dasarnya mencakup titik-titik pengetahuan penting dari multi-threading di Java. Setelah Anda menguasai poin pengetahuan pada gambar di atas, Anda pada dasarnya akan menguasai multi-threading di Java. Terutama termasuk:
Benang Java memiliki lima status dasar
Status baru (baru): Ketika pasangan objek utas dibuat, ia memasuki keadaan baru, seperti: thread t = mythread baru ();
Status siap (runnable): Ketika metode start () dari objek utas (t.start ();), utas memasuki keadaan siap. Sebuah utas dalam keadaan siap hanya berarti bahwa utas sudah siap dan sedang menunggu CPU untuk menjadwalkan eksekusi kapan saja, bukan berarti utas akan dieksekusi segera setelah t.start () dieksekusi;
Status Menjalankan: Ketika CPU mulai menjadwalkan utas dalam keadaan siap, utas dapat benar -benar dieksekusi, yaitu, ia memasuki keadaan berjalan. Catatan: Keadaan siap adalah satu -satunya entri ke keadaan berjalan, yaitu, jika utas ingin memasuki status berjalan untuk dieksekusi, pertama -tama harus dalam keadaan siap;
Status yang diblokir: Untuk beberapa alasan, utas dalam keadaan berjalan sementara menyerah penggunaan CPU dan menghentikan eksekusi. Pada saat ini, ia memasuki keadaan pemblokiran. Tidak akan memiliki kesempatan untuk dipanggil oleh CPU lagi untuk memasuki keadaan berjalan. Menurut alasan pemblokiran, status pemblokiran dapat dibagi menjadi tiga jenis:
1. Menunggu untuk memblokir: utas dalam keadaan berjalan mengeksekusi metode tunggu () untuk membuat utas memasuki status pemblokiran menunggu;
2. Pemblokiran yang disinkronkan- Utas gagal untuk memperoleh kunci sinkronisasi yang disinkronkan (karena kunci ditempati oleh utas lain), itu akan memasuki keadaan pemblokiran yang disinkronkan;
3. Pemblokiran Lainnya-Utas akan memasuki 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.
Mati: Utas telah selesai mengeksekusi atau keluar dari metode run () karena pengecualian, dan utas mengakhiri siklus hidupnya.
2. Penciptaan dan startup java multithreads
Ada tiga bentuk dasar pembuatan utas di java
1. Mewarahkan kelas utas dan mengesampingkan metode run () dari kelas.
kelas mythread memperluas utas {private int i = 0; @Override public void run () {for (i = 0; i <100; i ++) {System.out.println (thread.currentThread (). GetName () + "" + i); }}} Public Class ThreadTest {public static void main (string [] args) {for (int i = 0; i <100; i ++) {System.out.println (thread.currentThread (). getName () + "" + i); if (i == 30) {thread myThread1 = new mythread (); // Buat utas baru myThread1 utas ini memasuki utas negara baru myThread2 = mythread baru (); // Buat utas baru MyThread2 utas ini memasuki status baru myThread1.start (); // Panggil metode start () untuk membuat utas masukkan status siap mythread2.start (); // Hubungi metode start () untuk membuat utas masukkan status siap}}}}Seperti yang ditunjukkan di atas, mewarisi kelas utas, mythread kelas utas baru ditentukan dengan menimpa metode run (), di mana badan metode metode run () mewakili tugas yang perlu diselesaikan oleh utas, dan disebut badan eksekusi utas. Saat membuat objek kelas utas ini, utas baru dibuat dan memasuki status utas baru. Dengan memanggil metode start () yang dirujuk oleh objek utas, utas memasuki keadaan siap. Pada saat ini, utas mungkin tidak dieksekusi segera, tergantung pada waktu penjadwalan CPU.
2. Menerapkan antarmuka runnable dan mengesampingkan metode run () dari antarmuka. Metode run () juga merupakan badan eksekusi utas, membuat instance dari kelas implementasi runnable, dan menggunakan instance ini sebagai target kelas utas untuk membuat objek utas. Objek utas adalah objek utas asli.
kelas myRunnable mengimplementasikan runnable {private int i = 0; @Override public void run () {for (i = 0; i <100; i ++) {System.out.println (thread.currentThread (). GetName () + "" + i); }}} Public Class ThreadTest {public static void main (string [] args) {for (int i = 0; i <100; i ++) {System.out.println (thread.currentThread (). getName () + "" + i); if (i == 30) {runnable myrunnable = new myrunnable (); // Buat objek dari thread kelas implementasi runnable thread1 = utas baru (myRunnable); // Buat utas baru dengan myRunnable sebagai utas thread target thread2 = utas baru (myRunnable); thread1.start (); // Panggil metode start () untuk membuat utas masukkan thread status siap saji2.start (); }}}} Saya percaya bahwa semua orang akrab dengan dua cara di atas untuk membuat utas baru. Jadi apa hubungan antara utas dan runnable? Mari kita lihat contoh berikut.
Public Class ThreadTest {public static void main (string [] args) {for (int i = 0; i <100; i ++) {System.out.println (thread.currentThread (). getName () + "" + i); if (i == 30) {runnable myrunnable = new myrunnable (); Thread thread = mythread baru (myRunnable); thread.start (); }}}} kelas myRunnable mengimplementasikan runnable {private int i = 0; @Override public void run () {System.out.println ("di MyRunnable run"); untuk (i = 0; i <100; i ++) {System.out.println (thread.currentThread (). getName () + "" + i); }}} kelas mythread memperluas utas {private int i = 0; mythread publik (runnable runnable) {super (runnable); } @Override public void run () {System.out.println ("in mythread run"); untuk (i = 0; i <100; i ++) {System.out.println (thread.currentThread (). getName () + "" + i); }}}Demikian pula, hal yang sama berlaku untuk membuat utas yang mengimplementasikan antarmuka runnable, perbedaannya adalah bahwa
1 Thread Thread = MyThread baru (MyRunnable);
Jadi bisakah metode ini berhasil membuat utas baru? Jawabannya adalah ya. Adapun badan eksekusi utas saat ini, apakah metode run () dalam antarmuka myRunnable atau metode run () di kelas mythread? Melalui output, kita tahu bahwa badan eksekusi utas adalah metode run () di kelas MyThread. Faktanya, alasannya sangat sederhana, karena kelas utas itu sendiri juga mengimplementasikan antarmuka yang dapat dijalankan, dan metode run () pertama kali didefinisikan dalam antarmuka runnable.
antarmuka publik runnable {public abstrak void run (); } Mari kita lihat implementasi metode run () di antarmuka runnable di kelas utas:
@Override public void run () {if (target! = Null) {target.run (); }}Dengan kata lain, ketika menjalankan metode run () di kelas utas, pertama -tama akan menentukan apakah target ada. Jika ada, metode run () dalam target dieksekusi, yaitu metode run () di kelas yang mengimplementasikan antarmuka runnable dan menimpa metode run (). Namun, dalam kolom yang diberikan di atas, karena adanya polimorfisme, metode run () di kelas utas tidak dieksekusi sama sekali, tetapi jenis runtime, yaitu, metode run () di kelas Mythread dieksekusi secara langsung.
3. Buat utas menggunakan antarmuka yang dapat dipanggil dan mendatang. Secara khusus, ini menciptakan kelas implementasi untuk antarmuka yang dapat dipanggil dan mengimplementasikan metode Clall (). Dan gunakan kelas Futuretask untuk membungkus objek kelas implementasi yang dapat dipanggil, dan gunakan objek Futuretask ini sebagai target objek utas untuk membuat utas.
Tampaknya agak rumit, tetapi akan jelas jika Anda melihat contoh secara langsung.
Public Class ThreadTest {public static void main (string [] args) {callable <integer> mycallable = new mycallable (); // Buat objek MyCallable FutureTask <Integer> ft = futuretask baru <Integer> (myCallable); // Gunakan FutureTask untuk membungkus objek yang dapat diterbitkan untuk (int i = 0; i <100; i ++) {System.out.println (thread.currentThread (). GetName () + "" + i); if (i == 30) {thread thread = thread baru (ft); // Objek Futuretask membuat utas baru sebagai target objek utas thread.start (); // utas memasuki status siap}} system.out.println ("Utas utama untuk loop telah dieksekusi .."); coba {int sum = ft.get (); // Dapatkan hasilnya dikembalikan dengan metode call () dalam sistem utas baru yang baru dibuat.out.println ("sum =" + sum); } catch (InterruptedException e) {E.PrintStackTrace (); } catch (executionException e) {e.printstacktrace (); }}} kelas MyCallable mengimplementasikan Callable <Integer> {private int i = 0; // Tidak seperti metode run (), metode Call () memiliki nilai pengembalian @Override Public Integer call () {int sum = 0; untuk (; i <100; i ++) {System.out.println (thread.currentThread (). getName () + "" + i); jumlah += i; } return sum; }}Pertama -tama, kami menemukan bahwa dalam mengimplementasikan antarmuka yang dapat dipanggil, metode run () bukan lagi metode run (), tetapi metode call (). Metode panggilan () ini adalah badan eksekusi utas dan juga memiliki nilai pengembalian! Saat membuat utas baru, objek MyCallable dibungkus melalui FutureTask dan juga berfungsi sebagai target untuk objek utas. Kemudian lihat definisi kelas Futuretask:
kelas publik futuretask <v> mengimplementasikan runnableFuture <v> {// ....} antarmuka publik runnableFuture <V> memperluas runnable, masa depan <v> {void run (); }Oleh karena itu, kami menemukan bahwa kelas FutureTask sebenarnya mengimplementasikan antarmuka yang dapat dijalankan dan di masa depan, yang membuatnya memiliki karakteristik ganda masa depan dan dapat dijalankan. Melalui fitur Runnable, dapat digunakan sebagai target objek utas, dan fitur masa depan memungkinkannya untuk mendapatkan nilai pengembalian dari metode panggilan () di utas yang baru dibuat.
Setelah menjalankan program ini, kami menemukan bahwa SUM = 4950 selalu merupakan output terakhir. "Utas utama untuk loop telah dieksekusi ..." kemungkinan akan menjadi output di tengah loop utas anak. Dari mekanisme penjadwalan utas CPU, kita tahu bahwa tidak ada masalah dengan waktu output "utas utama untuk loop telah dieksekusi ...", jadi mengapa sum = 4950 menjadi output selamanya?
Alasannya adalah bahwa ketika metode call thread anak () diperoleh melalui metode ft.get (), ketika metode utas anak belum dieksekusi, metode ft.get () akan memblokir sampai metode call () dijalankan sebelum nilai pengembalian dapat diperoleh.
Di atas terutama menjelaskan tiga metode pembuatan utas umum. Untuk startup utas, mereka semua disebut metode start () dari objek utas. Penting untuk dicatat bahwa metode start () tidak dapat dipanggil dua kali pada objek utas yang sama.
AKU AKU AKU. Status siap, lari dan mati dari java multithreading
Keadaan siap dikonversi ke keadaan berjalan: ketika utas ini mendapatkan sumber daya prosesor;
Keadaan berjalan dikonversi ke keadaan siap: ketika utas ini secara aktif memanggil metode hasil () atau kehilangan sumber daya prosesor selama berjalan.
Keadaan berjalan dikonversi ke keadaan mati: Ketika badan eksekusi utas selesai atau pengecualian terjadi.
Perlu dicatat di sini bahwa ketika metode hasil () dari utas dipanggil, utas transisi dari keadaan berjalan ke keadaan siap, tetapi utas mana dalam keadaan siap CPU dijadwalkan memiliki keacakan tertentu. Oleh karena itu, dapat terjadi bahwa setelah thread memanggil metode hasil (), CPU masih menjadwalkan utas A.
Karena kebutuhan bisnis yang sebenarnya, sering kali ditemukan bahwa utas perlu diakhiri pada kesempatan tertentu untuk membuatnya memasuki keadaan mati. Metode yang paling umum saat ini adalah mengatur variabel boolean, dan ketika kondisinya dipenuhi, badan eksekusi utas akan dieksekusi dengan cepat. menyukai:
Public Class ThreadTest {public static void main (string [] args) {myRunnable myrunnable = new myrunnable (); Thread thread = utas baru (myRunnable); untuk (int i = 0; i <100; i ++) {System.out.println (thread.currentThread (). getName () + "" + i); if (i == 30) {thread.start (); } if (i == 40) {MyRunnable.StopThread (); }}}} kelas myRunnable mengimplementasikan runnable {private boolean stop; @Override public void run () {for (int i = 0; i <100 &&! Stop; i ++) {System.out.println (thread.currentThread (). GetName () + "" + i); }} public void stopThread () {this.stop = true; }}Kami akan terus memilah artikel terkait di masa depan. Terima kasih atas dukungan Anda untuk situs ini!
Serangkaian artikel:
Penjelasan Java Multi-Threaded Instances (I)
Penjelasan terperinci tentang Java Multi-Threaded Instances (II)
Penjelasan terperinci tentang Java Multi-Threaded Instances (III)