Java 101 bulan ini mengakhiri rangkaian thread dengan berfokus pada grup thread, volatilitas, variabel thread-lokal, timer, dan ThreadDeath
kelas.
Memahami utas Java - baca keseluruhan seri
- Bagian 1: Memperkenalkan utas dan runnable
- Bagian 2: Sinkronisasi benang
- Bagian 3: Penjadwalan thread, tunggu / beri tahu, dan gangguan thread
- Bagian 4: Grup thread, volatilitas, variabel thread-lokal, timer, dan kematian thread
Grup benang
Dalam program server jaringan, satu utas menunggu dan menerima permintaan dari program klien untuk dieksekusi, misalnya, transaksi database atau kalkulasi kompleks. Utas biasanya membuat utas baru untuk menangani permintaan. Bergantung pada volume permintaan, banyak utas berbeda mungkin hadir secara bersamaan, mempersulit manajemen utas. Untuk menyederhanakan manajemen utas, program mengatur utas mereka dengan grup utas - java.lang.ThreadGroup
objek yang mengelompokkan objek utas Thread
(dan Thread
subkelas) terkait. Misalnya, program Anda dapat menggunakan ThreadGroup
untuk mengelompokkan semua utas pencetakan ke dalam satu grup.
Catatan: Agar diskusi tetap sederhana, saya merujuk ke grup utas seolah-olah mereka mengatur utas. Pada kenyataannya, grup utas mengatur Thread
(dan Thread
subkelas) objek yang terkait dengan utas.
Java mengharuskan setiap utas dan setiap grup utas — simpan grup utas akar, system
—untuk bergabung dengan beberapa grup utas lainnya. Pengaturan tersebut mengarah ke struktur grup thread hierarkis, yang diilustrasikan gambar di bawah ini dalam konteks aplikasi.

Di bagian atas struktur gambar adalah system
grup utas. Grup yang dibuat system
JVM mengatur utas JVM yang menangani penyelesaian objek dan tugas sistem lainnya, dan berfungsi sebagai grup utas akar dari struktur grup utas hierarki aplikasi. Tepat di bawah system
ini adalah main
grup utas yang dibuat JVM , yang merupakan system
grup subjudul (subgrup, singkatnya). main
berisi setidaknya satu utas — utas utama buatan JVM yang menjalankan instruksi kode byte dalam main()
metode tersebut.
Di bawah main
grup berada subgroup 1
dan subgroup 2
subkelompok, subkelompok yang dibuat oleh aplikasi (yang dibuat oleh aplikasi gambar). Selanjutnya, subgroup 1
kelompok tiga benang aplikasi-dibuat: thread 1
, thread 2
, dan thread 3
. Sebaliknya, subgroup 2
kelompok satu aplikasi yang dibuat thread: my thread
.
Sekarang setelah Anda mengetahui dasar-dasarnya, mari mulai membuat grup utas.
Buat grup utas dan kaitkan utas dengan grup itu
The ThreadGroup
kelas dokumentasi SDK mengungkapkan dua konstruktor: ThreadGroup(String name)
dan ThreadGroup(ThreadGroup parent, String name)
. Kedua konstruktor membuat grup utas dan memberinya nama, seperti yang name
ditentukan oleh parameter. Konstruktor berbeda dalam memilih grup utas mana yang berfungsi sebagai induk grup utas yang baru dibuat. Setiap grup utas, kecuali system
, harus memiliki grup utas induk. Sebab ThreadGroup(String name)
, induk adalah grup utas dari utas yang memanggil ThreadGroup(String name)
. Sebagai contoh, jika utas utama memanggil ThreadGroup(String name)
, grup utas yang baru dibuat memiliki grup utas utama sebagai induk— main
. Sebab ThreadGroup(ThreadGroup parent, String name)
, orang tua adalah kelompok yang menjadi parent
rujukan. Kode berikut menunjukkan cara menggunakan konstruktor ini untuk membuat sepasang grup untaian:
public static void main (String [] args) { ThreadGroup tg1 = new ThreadGroup ("A"); ThreadGroup tg2 = new ThreadGroup (tg1, "B"); }
Pada kode di atas, utas utama membuat dua grup utas: A
dan B
. Pertama, utas utama membuat A
dengan memanggil ThreadGroup(String name)
. The tg1
orangtua benang kelompok -referenced adalah main
karena main
merupakan kelompok benang benang utama. Kedua, utas utama membuat B
dengan memanggil ThreadGroup(ThreadGroup parent, String name)
. The tg2
orangtua benang kelompok -referenced adalah A
karena tg1
referensi 's melewati sebagai argumen untuk ThreadGroup (tg1, "B")
dan A
rekan dengan tg1
.
Tip: Setelah Anda tidak perlu lagi hirarki ThreadGroup
objek, panggilan ThreadGroup
's void destroy()
metode melalui referensi ke ThreadGroup
objek di bagian atas hirarki itu. Jika ThreadGroup
objek teratas dan semua objek subkelompok kekurangan objek thread, destroy()
persiapkan objek grup thread tersebut untuk pengumpulan sampah. Jika tidak, destroy()
lempar IllegalThreadStateException
benda. Namun, hingga Anda membatalkan referensi ke ThreadGroup
objek teratas (dengan asumsi variabel bidang berisi referensi tersebut), pengumpul sampah tidak dapat mengumpulkan objek tersebut. Referensi objek atas, Anda dapat menentukan apakah panggilan sebelumnya dibuat dengan destroy()
metode dengan memanggil ThreadGroup
's boolean isDestroyed()
metode. Metode itu mengembalikan nilai true jika hierarki grup untaian dihancurkan.
Dengan sendirinya, grup utas tidak berguna. Agar bisa berguna, mereka harus mengelompokkan utas. Anda mengelompokkan utas menjadi grup utas dengan meneruskan ThreadGroup
referensi ke Thread
konstruktor yang sesuai :
ThreadGroup tg = new ThreadGroup ("subgroup 2"); Thread t = new Thread (tg, "my thread");
Kode di atas terlebih dahulu membuat subgroup 2
grup dengan main
sebagai grup induk. (Saya berasumsi utas utama mengeksekusi kode.) Kode selanjutnya membuat my thread
Thread
objek dalam subgroup 2
grup.
Sekarang, mari buat aplikasi yang menghasilkan struktur grup thread hierarki gambar kita:
Kode 1. ThreadGroupDemo.java
// ThreadGroupDemo.java class ThreadGroupDemo { public static void main (String [] args) { ThreadGroup tg = new ThreadGroup ("subgroup 1"); Thread t1 = new Thread (tg, "thread 1"); Thread t2 = new Thread (tg, "thread 2"); Thread t3 = new Thread (tg, "thread 3"); tg = new ThreadGroup ("subgroup 2"); Thread t4 = new Thread (tg, "my thread"); tg = Thread.currentThread ().getThreadGroup (); int agc = tg.activeGroupCount (); System.out.println ("Active thread groups in " + tg.getName () + " thread group: " + agc); tg.list (); } }
ThreadGroupDemo
membuat grup utas dan objek utas yang sesuai untuk mencerminkan apa yang Anda lihat pada gambar di atas. Untuk membuktikan bahwa grup subgroup 1
dan subgroup 2
adalah main
satu-satunya subgrup, ThreadGroupDemo
lakukan hal berikut:
- Memperoleh kembali referensi ke thread utama
ThreadGroup
objek dengan memanggilThread
'statis scurrentThread()
metode (yang mengembalikan referensi ke thread utamaThread
objek) diikuti olehThread
' sThreadGroup getThreadGroup()
metode. - Panggilan
ThreadGroup
'sint activeGroupCount()
metode pada hanya-kembaliThreadGroup
referensi untuk kembali perkiraan kelompok yang aktif dalam kelompok benang benang utama. - Panggilan
ThreadGroup
'sString getName ()
metode untuk kembali nama grup benang benang utama. - Panggilan
ThreadGroup
'svoid list ()
metode untuk mencetak pada standar rincian perangkat output pada kelompok benang benang utama dan semua subkelompok.
Saat dijalankan, ThreadGroupDemo
menampilkan output berikut:
Active thread groups in main thread group: 2 java.lang.ThreadGroup[name=main,maxpri=10] Thread[main,5,main] Thread[Thread-0,5,main] java.lang.ThreadGroup[name=subgroup 1,maxpri=10] Thread[thread 1,5,subgroup 1] Thread[thread 2,5,subgroup 1] Thread[thread 3,5,subgroup 1] java.lang.ThreadGroup[name=subgroup 2,maxpri=10] Thread[my thread,5,subgroup 2]
Output yang dimulai dengan Thread
hasil dari list()
'panggilan s internal untuk Thread
' s toString()
metode, format output yang saya jelaskan di Bagian 1. Seiring dengan output yang, Anda melihat output dimulai dengan java.lang.ThreadGroup
. Keluaran tersebut mengidentifikasi nama grup utas diikuti dengan prioritas maksimumnya.
Prioritas dan grup utas
Prioritas maksimum grup utas adalah prioritas tertinggi yang dapat dicapai utas mana pun. Pertimbangkan program server jaringan yang disebutkan di atas. Dalam program itu, utas menunggu dan menerima permintaan dari program klien. Sebelum melakukan itu, utas tunggu / terima-permintaan mungkin terlebih dahulu membuat grup utas dengan prioritas maksimum tepat di bawah prioritas utas itu. Nanti, ketika sebuah permintaan tiba, utas tunggu-untuk / terima-permintaan membuat utas baru untuk menanggapi permintaan klien dan menambahkan utas baru ke grup utas yang dibuat sebelumnya. Prioritas utas baru secara otomatis diturunkan ke maksimum grup utas. Dengan begitu, thread wait-for / accept-request merespons permintaan lebih sering karena lebih sering dijalankan.
Java memberikan prioritas maksimum untuk setiap grup utas. Saat Anda membuat grup, Java mendapatkan prioritas tersebut dari grup induknya. Gunakan ThreadGroup
's void setMaxPriority(int priority)
metode untuk selanjutnya mengatur prioritas maksimal. Setiap utas yang Anda tambahkan ke grup setelah mengatur prioritas maksimumnya tidak dapat memiliki prioritas yang melebihi maksimum. Setiap utas dengan prioritas lebih tinggi secara otomatis turun ketika bergabung dengan grup utas. Namun, jika Anda menggunakan setMaxPriority(int priority)
untuk menurunkan prioritas maksimum grup, semua utas yang ditambahkan ke grup sebelum panggilan metode tersebut tetap mempertahankan prioritas aslinya. Misalnya, jika Anda menambahkan utas prioritas 8 ke grup prioritas maksimum 9, dan kemudian menurunkan prioritas maksimum grup itu ke 7, utas prioritas 8 tetap berada di prioritas 8. Setiap saat, Anda dapat menentukan grup utas 's prioritas maksimum dengan memanggil ThreadGroup
'sint getMaxPriority()
metode. Untuk mendemonstrasikan prioritas dan grup utas, saya menulis MaxPriorityDemo
:
Daftar 2. MaxPriorityDemo.java
// MaxPriorityDemo.java class MaxPriorityDemo { public static void main (String [] args) { ThreadGroup tg = new ThreadGroup ("A"); System.out.println ("tg maximum priority = " + tg.getMaxPriority ()); Thread t1 = new Thread (tg, "X"); System.out.println ("t1 priority = " + t1.getPriority ()); t1.setPriority (Thread.NORM_PRIORITY + 1); System.out.println ("t1 priority after setPriority() = " + t1.getPriority ()); tg.setMaxPriority (Thread.NORM_PRIORITY - 1); System.out.println ("tg maximum priority after setMaxPriority() = " + tg.getMaxPriority ()); System.out.println ("t1 priority after setMaxPriority() = " + t1.getPriority ()); Thread t2 = new Thread (tg, "Y"); System.out.println ("t2 priority = " + t2.getPriority ()); t2.setPriority (Thread.NORM_PRIORITY); System.out.println ("t2 priority after setPriority() = " + t2.getPriority ()); } }
Saat dijalankan, MaxPriorityDemo
menghasilkan output berikut:
tg maximum priority = 10 t1 priority = 5 t1 priority after setPriority() = 6 tg maximum priority after setMaxPriority() = 4 t1 priority after setMaxPriority() = 6 t2 priority = 4 t2 priority after setPriority() = 4
Grup untaian A
(yang tg
mereferensikan) dimulai dengan prioritas tertinggi (10) sebagai maksimumnya. Thread X
, yang Thread
objeknya t1
mereferensikan, bergabung dengan grup dan menerima 5 sebagai prioritasnya. Kami mengubah prioritas utas menjadi 6, yang berhasil karena 6 kurang dari 10. Selanjutnya, kami memanggil setMaxPriority(int priority)
untuk mengurangi prioritas maksimum grup menjadi 4. Meskipun utas X
tetap pada prioritas 6, Y
utas yang baru ditambahkan menerima 4 sebagai prioritasnya. Akhirnya, upaya untuk meningkatkan Y
prioritas utas ke 5 gagal, karena 5 lebih besar dari 4.
Catatan:setMaxPriority(int priority)
secara otomatis menyesuaikan prioritas maksimum subgrup grup topik.
Selain menggunakan grup utas untuk membatasi prioritas utas, Anda bisa menyelesaikan tugas lain dengan memanggil berbagai ThreadGroup
metode yang berlaku untuk tiap utas grup. Metode meliputi void suspend()
, void resume()
, void stop()
, dan void interrupt()
. Karena Sun Microsystems telah menghentikan tiga metode pertama (mereka tidak aman), kami hanya memeriksanya interrupt()
.
Interupsi grup utas
ThreadGroup
's interrupt()
metode memungkinkan thread untuk mengganggu benang dan subkelompok kelompok benang khusus ini. Teknik ini akan terbukti sesuai dalam skenario berikut: Rangkaian utama aplikasi Anda membuat beberapa utas yang masing-masing menjalankan satu unit kerja. Karena semua utas harus menyelesaikan unit kerjanya masing-masing sebelum utas apa pun dapat memeriksa hasilnya, setiap utas menunggu setelah menyelesaikan unit kerjanya. Utas utama memantau status kerja. Setelah semua utas lainnya menunggu, utas utama akan memanggil interrupt()
untuk mengganggu waktu tunggu utas lainnya. Kemudian utas tersebut dapat memeriksa dan memproses hasilnya. Kode 3 menunjukkan gangguan grup utas:
Kode 3. InterruptThreadGroup.java
// InterruptThreadGroup.java class InterruptThreadGroup { public static void main (String [] args) { MyThread mt = new MyThread (); mt.setName ("A"); mt.start (); mt = new MyThread (); mt.setName ("B"); mt.start (); try { Thread.sleep (2000); // Wait 2 seconds } catch (InterruptedException e) { } // Interrupt all methods in the same thread group as the main // thread Thread.currentThread ().getThreadGroup ().interrupt (); } } class MyThread extends Thread { public void run () { synchronized ("A") { System.out.println (getName () + " about to wait."); try { "A".wait (); } catch (InterruptedException e) { System.out.println (getName () + " interrupted."); } System.out.println (getName () + " terminating."); } } }