Java 101: Memahami benang Java, Bahagian 4: Kumpulan benang, turun naik, dan pemboleh ubah tempatan-utas

Java 101 bulan ini mengakhiri siri utas dengan memberi tumpuan kepada kumpulan utas, turun naik, pemboleh ubah benang-tempatan, pemasa, dan ThreadDeathkelas.

Memahami benang Java - baca keseluruhan siri

  • Bahagian 1: Memperkenalkan benang dan runnables
  • Bahagian 2: Penyegerakan benang
  • Bahagian 3: Penjadualan benang, tunggu / maklumkan, dan gangguan urutan
  • Bahagian 4: Kumpulan benang, turun naik, pemboleh ubah benang-tempatan, pemasa, dan kematian benang

Kumpulan benang

Dalam program pelayan rangkaian, satu utas menunggu dan menerima permintaan dari program klien untuk melaksanakan, misalnya, transaksi pangkalan data atau pengiraan yang kompleks. Benang biasanya membuat utas baru untuk menangani permintaan. Bergantung pada jumlah permintaan, banyak utas mungkin hadir secara serentak, menyukarkan pengurusan utas. Untuk mempermudah pengurusan utas, program menyusun utasnya dengan kumpulan utas - java.lang.ThreadGroupobjek yang mengelompokkan objek utas yang berkaitan Thread(dan Threadsubkelas). Sebagai contoh, program anda boleh digunakan ThreadGroupuntuk mengumpulkan semua utas percetakan menjadi satu kumpulan.

Catatan: Untuk mempermudah perbincangan, saya merujuk kepada kumpulan utas seolah-olah mereka menyusun utas. Pada hakikatnya, kumpulan utas menyusun Thread(dan Threadsubkelas) objek yang berkaitan dengan utas.

Java memerlukan setiap utas dan setiap kumpulan utas — simpan kumpulan systemutas akar — —untuk bergabung dengan beberapa kumpulan utas yang lain. Penyusunan itu membawa kepada struktur kumpulan utas hierarki, yang ditunjukkan oleh gambar di bawah dalam konteks aplikasi.

Di bahagian atas struktur angka adalah systemkumpulan utas. systemKumpulan yang dibuat oleh JVM menyusun utas JVM yang berurusan dengan penyelesaian objek dan tugas sistem lain, dan berfungsi sebagai kumpulan utas akar struktur kumpulan utas hierarki aplikasi. Di bawah ini systemadalah kumpulan utas yang dibuat oleh JVM main, yang merupakan systemkumpulan sub - benang (pendeknya subkumpulan). mainmengandungi sekurang-kurangnya satu utas — utas utama buatan JVM yang melaksanakan arahan kod byte dalam main()kaedah ini.

Di bawah mainkumpulan itu terdapat subkumpulan subgroup 1dan subgroup 2subkumpulan, subkumpulan yang dibuat aplikasi (yang dibuat oleh aplikasi angka). Tambahan pula, subgroup 1kumpulan tiga benang aplikasi dicipta: thread 1, thread 2, dan thread 3. Sebaliknya, subgroup 2kumpulan satu aplikasi dicipta thread: my thread.

Setelah anda mengetahui asasnya, mari mulakan membuat kumpulan utas.

Buat kumpulan utas dan kaitkan utas dengan kumpulan tersebut

The ThreadGroupdokumentasi SDK kelas ini mendedahkan dua pengeluar: ThreadGroup(String name)dan ThreadGroup(ThreadGroup parent, String name). Kedua-dua pembina membuat kumpulan utas dan memberikannya namanya, seperti yang nameditentukan oleh parameter. Pembina berbeza dalam pilihan mereka mengenai kumpulan utas apa yang berfungsi sebagai induk kepada kumpulan utas yang baru dibuat. Setiap kumpulan utas, kecuali system, mesti mempunyai kumpulan utas induk. Untuk ThreadGroup(String name), ibu bapa adalah kumpulan utas utas yang memanggil ThreadGroup(String name). Sebagai contoh, jika utas utama memanggil ThreadGroup(String name), kumpulan utas yang baru dibuat mempunyai kumpulan utas utama sebagai induknya— main. Sebab ThreadGroup(ThreadGroup parent, String name), ibu bapa adalah kumpulan yang parentmerujuk. Kod berikut menunjukkan cara menggunakan konstruktor ini untuk membuat sepasang kumpulan utas:

public static void main (String [] args) { ThreadGroup tg1 = new ThreadGroup ("A"); ThreadGroup tg2 = new ThreadGroup (tg1, "B"); }

Dalam kod di atas, utas utama membuat dua kumpulan utas: Adan B. Pertama, utas utama dibuat Adengan memanggil ThreadGroup(String name). Ibu tg1bapa kumpulan utas -referensi adalah mainkerana kumpulan utas utas mainutama. Kedua, utas utama dibuat Bdengan memanggil ThreadGroup(ThreadGroup parent, String name). Ibu tg2bapa kumpulan utas- rujukan adalah Akerana tg1rujukan berlalu sebagai hujah kepada ThreadGroup (tg1, "B")dan Amengaitkan dengan tg1.

Petua: Apabila anda tidak lagi memerlukan hierarki ThreadGroupobjek, panggilan ThreadGroup's void destroy()kaedah melalui rujukan kepada ThreadGroupobjek di bahagian atas hierarki itu. Sekiranya ThreadGroupobjek atas dan semua objek subkumpulan kekurangan objek destroy()utas , sediakan objek kumpulan utas tersebut untuk pengumpulan sampah. Jika tidak, destroy()baling IllegalThreadStateExceptionobjek. Namun, sehingga anda membatalkan rujukan ke ThreadGroupobjek teratas (dengan anggapan pemboleh ubah medan berisi rujukan itu), pengumpul sampah tidak dapat mengumpulkan objek tersebut. Rujukan objek atas, anda boleh menentukan sama ada panggilan sebelumnya telah dibuat kepada destroy()kaedah dengan memanggil ThreadGroup's boolean isDestroyed()kaedah. Kaedah itu kembali benar sekiranya hierarki kumpulan utas hancur.

Dengan sendirinya, kumpulan utas tidak berguna. Untuk kegunaan apa pun, mereka mesti mengelompokkan utas. Anda mengumpulkan benang menjadi kumpulan utas dengan menyampaikan ThreadGrouprujukan kepada Threadpembina yang sesuai :

ThreadGroup tg = new ThreadGroup ("subgroup 2"); Thread t = new Thread (tg, "my thread");

Kod di atas terlebih dahulu membuat subgroup 2kumpulan dengan mainsebagai kumpulan induk. (Saya menganggap utas utama melaksanakan kod.) Kod seterusnya membuat my threadThreadobjek dalam subgroup 2kumpulan.

Sekarang, mari buat aplikasi yang menghasilkan struktur kumpulan utas hierarki tokoh kami:

Penyenaraian 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 (); } }

ThreadGroupDemomembuat kumpulan benang dan objek utas yang sesuai untuk mencerminkan apa yang anda lihat dalam gambar di atas. Untuk membuktikan bahawa kumpulan subgroup 1dan subgroup 2kumpulan adalah mainsatu-satunya subkumpulan, ThreadGroupDemolakukan perkara berikut:

  1. Mendapatkan semula yang merujuk kepada thread utama ini ThreadGroupobjek dengan memanggil Thread'statik s currentThread()kaedah (yang mengembalikan sebutan mengenai thread utama ini Threadobjek) diikuti oleh Thread' s ThreadGroup getThreadGroup()kaedah.
  2. Panggilan ThreadGroup's int activeGroupCount()kaedah pada yang baru kembali ThreadGroupmerujuk kepada kembali satu anggaran kumpulan aktif dalam kumpulan benang benang utama ini.
  3. Panggilan ThreadGroup's String getName ()kaedah untuk kembali nama kumpulan benang benang utama ini.
  4. Panggilan ThreadGroup's void list ()kaedah untuk mencetak pada butiran peranti output standard kumpulan benang benang utama dan semua kumpulan kecil.

Semasa dijalankan, ThreadGroupDemomemaparkan 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 bermula dengan Threadkeputusan dari list()'panggilan dalaman s kepada Thread' s toString()kaedah, format output saya sebut dalam Bahagian 1. Bersama-sama dengan output itu, anda lihat output bermula dengan java.lang.ThreadGroup. Keluaran itu mengenal pasti nama kumpulan utas diikuti dengan keutamaan maksimumnya.

Kumpulan keutamaan dan utas

Keutamaan maksimum kumpulan utas adalah keutamaan tertinggi yang dapat dicapai oleh utasnya. Pertimbangkan program pelayan rangkaian 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 kumpulan utas dengan keutamaan maksimum tepat di bawah keutamaan utas itu. Kemudian, apabila permintaan tiba, utas tunggu / terima-permintaan membuat utas baru untuk bertindak balas terhadap permintaan pelanggan dan menambahkan utas baru ke kumpulan utas yang dibuat sebelumnya. Keutamaan utas baru secara automatik turun ke maksimum kumpulan utas. Dengan cara itu, utas tunggu / terima-permintaan lebih kerap bertindak balas terhadap permintaan kerana ia berjalan lebih kerap.

Java assigns a maximum priority to each thread group. When you create a group, Java obtains that priority from its parent group. Use ThreadGroup's void setMaxPriority(int priority) method to subsequently set the maximum priority. Any threads that you add to the group after setting its maximum priority cannot have a priority that exceeds the maximum. Any thread with a higher priority automatically lowers when it joins the thread group. However, if you use setMaxPriority(int priority) to lower a group's maximum priority, all threads added to the group prior to that method call keep their original priorities. For example, if you add a priority 8 thread to a maximum priority 9 group, and then lower that group's maximum priority to 7, the priority 8 thread remains at priority 8. At any time, you can determine a thread group's maximum priority by calling ThreadGroup's int getMaxPriority() method. To demonstrate priority and thread groups, I wrote MaxPriorityDemo:

Listing 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 ()); } }

When run, MaxPriorityDemo produces the following output:

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

Thread group A (which tg references) starts with the highest priority (10) as its maximum. Thread X, whose Thread object t1 references, joins the group and receives 5 as its priority. We change that thread's priority to 6, which succeeds because 6 is less than 10. Subsequently, we call setMaxPriority(int priority) to reduce the group's maximum priority to 4. Although thread X remains at priority 6, a newly-added Y thread receives 4 as its priority. Finally, an attempt to increase thread Y's priority to 5 fails, because 5 is greater than 4.

Note:setMaxPriority(int priority) automatically adjusts the maximum priority of a thread group's subgroups.

In addition to using thread groups to limit thread priority, you can accomplish other tasks by calling various ThreadGroup methods that apply to each group's thread. Methods include void suspend(), void resume(), void stop(), and void interrupt(). Because Sun Microsystems has deprecated the first three methods (they are unsafe), we examine only interrupt().

Interrupt a thread group

ThreadGroup's interrupt()kaedah membolehkan benang untuk mengganggu benang dan kumpulan kecil benang kumpulan khusus. Teknik ini akan terbukti sesuai dalam senario berikut: Benang utama aplikasi anda menghasilkan banyak utas yang masing-masing melakukan satu unit kerja. Oleh kerana semua utas mesti menyelesaikan unit kerja masing-masing sebelum sebarang utas dapat memeriksa hasilnya, setiap utas menunggu setelah menyelesaikan unit kerjanya. Benang utama memantau keadaan kerja. Setelah semua utas lain menunggu, utas utama memanggil interrupt()untuk mengganggu penantian utas yang lain. Kemudian utas tersebut dapat memeriksa dan memproses hasilnya. Penyenaraian 3 menunjukkan gangguan kumpulan utas:

Penyenaraian 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."); } } }