Pengenalan benang Java

Artikel ini, salah satu yang pertama diterbitkan oleh JavaWorld, menerangkan bagaimana utas dilaksanakan dalam bahasa pengaturcaraan Java, dimulai dengan gambaran umum utas.

Ringkasnya, utas adalah jalan pelaksanaan program. Sebilangan besar program yang ditulis hari ini berjalan sebagai satu utas, menyebabkan masalah apabila banyak peristiwa atau tindakan perlu berlaku pada masa yang sama. Katakan, sebagai contoh, program tidak mampu melukis gambar semasa membaca ketukan kekunci. Program mesti memberi perhatian penuh pada input papan kekunci yang tidak memiliki kemampuan untuk menangani lebih dari satu acara pada satu masa. Penyelesaian ideal untuk masalah ini adalah pelaksanaan dua bahagian atau lebih program dengan lancar pada masa yang sama. Benang membolehkan kita melakukan ini.

Belajar mengenai benang Java

Artikel ini adalah sebahagian daripada arkib kandungan teknikal JavaWorld. Lihat yang berikut untuk mengetahui lebih lanjut mengenai utas dan serentak Java:

Memahami benang Java ( siri Java 101 , 2002):

  • Bahagian 1: Memperkenalkan benang dan runnables
  • Bahagian 2: Penyegerakan benang
  • Bahagian 3: Penjadualan benang dan tunggu / maklumkan
  • Bahagian 4: Kumpulan benang dan turun naik

Artikel berkaitan

  • Java berulir hiper: Menggunakan Java Concurrency API (2006)
  • Monitor yang lebih baik untuk program multithreaded (2007)
  • Memahami kesesuaian Pelakon, Bahagian 1 (2009)
  • Pengesanan dan pengendalian benang gantung (2011)

Periksa juga peta laman web dan mesin carian JavaWorld .

Aplikasi multithreaded memberikan kekuatan kuat mereka dengan menjalankan banyak utas secara serentak dalam satu program. Dari sudut pandang logik, multithreading bermaksud beberapa baris program tunggal dapat dijalankan pada masa yang sama, namun, tidak sama dengan memulakan program dua kali dan mengatakan bahawa terdapat beberapa baris program yang dijalankan pada masa yang sama masa. Dalam kes ini, sistem operasi menganggap program sebagai dua proses yang terpisah dan berbeza. Di bawah Unix, proses forking membuat proses anak dengan ruang alamat yang berbeza untuk kod dan data. Walau bagaimanapun,fork()menghasilkan banyak overhead untuk sistem operasi, menjadikannya operasi yang sangat intensif CPU. Sebagai ganti dengan memulakan utas, jalan pelaksanaan yang cekap dibuat sementara masih berkongsi kawasan data asal dari ibu bapa. Idea untuk berkongsi kawasan data sangat bermanfaat, tetapi membawa beberapa bidang perhatian yang akan kita bincangkan kemudian.

Membuat utas

Pencipta Java telah merancang dengan baik dua cara untuk membuat utas: melaksanakan antara muka dan memperluas kelas. Memperluas kelas adalah cara Java mewarisi kaedah dan pemboleh ubah dari kelas induk. Dalam kes ini, seseorang hanya boleh melanjutkan atau mewarisi dari kelas induk tunggal. Batasan ini di dalam Java dapat diatasi dengan menerapkan antaramuka, yang merupakan cara paling umum untuk membuat utas. (Perhatikan bahawa tindakan mewarisi hanya membenarkan kelas dijalankan sebagai utas. Terserah kepada kelas untuk start()dilaksanakan, dll.)

Antaramuka menyediakan cara bagi pengaturcara untuk meletakkan asas kelas. Mereka digunakan untuk merancang keperluan untuk sekumpulan kelas yang akan dilaksanakan. Antaramuka mengatur segalanya, dan kelas atau kelas yang melaksanakan antara muka melakukan semua kerja. Kumpulan kelas yang berbeza yang melaksanakan antara muka harus mengikuti peraturan yang sama.

Terdapat beberapa perbezaan antara kelas dan antara muka. Pertama, antara muka hanya boleh mengandungi kaedah abstrak dan / atau pemboleh ubah akhir statik (pemalar). Kelas, sebaliknya, dapat melaksanakan kaedah dan mengandungi pemboleh ubah yang bukan pemalar. Kedua, antara muka tidak dapat melaksanakan kaedah apa pun. Kelas yang melaksanakan antara muka mesti melaksanakan semua kaedah yang ditentukan dalam antara muka tersebut. Antaramuka mempunyai kemampuan untuk meluas dari antara muka lain, dan (tidak seperti kelas) dapat meluas dari pelbagai antara muka. Tambahan pula, antara muka tidak dapat dibuat dengan operator baru; sebagai contoh, Runnable a=new Runnable();tidak dibenarkan.

Kaedah pertama untuk membuat utas adalah dengan meluas dari Threadkelas. Lakukan ini hanya jika kelas yang anda perlukan dijalankan sebagai utas tidak perlu dilanjutkan dari kelas lain. The Threadkelas ditakrifkan dalam java.lang pakej, yang perlu diimport supaya kelas kami mengetahui pentakrifan.

import java.lang.*; public class Counter extends Thread { public void run() { .... } }

Contoh di atas mewujudkan kelas baru Counteryang memperluas Threadkelas dan mengesampingkan Thread.run()kaedah untuk pelaksanaannya sendiri. The run()kaedah adalah di mana semua kerja-kerja yang Counterthread kelas dilakukan. Kelas yang sama dapat dibuat dengan melaksanakan Runnable:

import java.lang.*; public class Counter implements Runnable { Thread T; public void run() { .... } }

Di sini, run()kaedah abstrak ditakrifkan dalam antara muka Runnable dan sedang dilaksanakan. Perhatikan bahawa kita mempunyai contoh Threadkelas sebagai pemboleh ubah Counterkelas. Satu-satunya perbezaan antara kedua kaedah tersebut ialah dengan melaksanakan Runnable, terdapat fleksibiliti yang lebih besar dalam pembuatan kelas Counter. Dalam contoh di atas, peluang masih ada untuk melanjutkan Counterkelas, jika diperlukan. Sebilangan besar kelas yang dibuat yang perlu dijalankan sebagai utas akan melaksanakan Runnable kerana mereka mungkin memperluas fungsi lain dari kelas lain.

Jangan berfikir bahawa antara muka Runnable melakukan kerja sebenar semasa thread sedang dijalankan. Ia hanyalah kelas yang dibuat untuk memberi idea mengenai reka bentuk Threadkelas. Sebenarnya, ia sangat kecil yang hanya mengandungi satu kaedah abstrak. Inilah definisi antara muka Runnable secara langsung dari sumber Java:

package java.lang; public interface Runnable { public abstract void run(); }

Itu sahaja yang ada pada antara muka Runnable. Antaramuka hanya menyediakan reka bentuk di mana kelas harus dilaksanakan. Dalam kes antara muka Runnable, ia memaksa definisi run()kaedah sahaja . Oleh itu, sebahagian besar kerja dilakukan di Threadkelas. Melihat lebih dekat pada bahagian dalam definisi Threadkelas akan memberi idea tentang apa yang sebenarnya berlaku:

public class Thread implements Runnable { ... public void run() { if (target != null) { target.run(); } } ... }

Dari coretan kod di atas terbukti bahawa kelas Thread juga menerapkan antara muka Runnable. Thread. run()memeriksa untuk memastikan bahawa kelas sasaran (kelas yang akan dijalankan sebagai utas) tidak sama dengan nol, dan kemudian melaksanakan run()kaedah sasaran. Apabila ini berlaku, run()kaedah sasaran akan dijalankan sebagai utasnya sendiri.

Memulakan dan berhenti

Oleh kerana cara yang berbeza untuk membuat contoh utas kini sudah jelas, kami akan membincangkan pelaksanaan utas bermula dengan cara yang tersedia untuk memulakan dan menghentikannya menggunakan applet kecil yang berisi utas untuk menggambarkan mekanik:

Contoh dan kod Sumber CounterThread

Applet di atas akan mula dihitung dari 0 yang memaparkan outputnya ke skrin dan konsol. Sekilas sekilas mungkin memberi kesan bahawa program akan mulai menghitung dan menampilkan setiap angka, tetapi ini tidak terjadi. Pemeriksaan yang lebih teliti terhadap pelaksanaan applet ini akan menunjukkan identiti sebenarnya.

Dalam kes ini, CounterThreadkelas terpaksa melaksanakan Runnable kerana memperluas Applet kelas. Seperti dalam semua applet, init()kaedah ini dijalankan terlebih dahulu. Dalam init(), Pembolehubah pembolehubah dimulakan menjadi sifar dan contoh baru Threadkelas dibuat. Dengan meneruskan thiske Threadkonstruktor, utas baru akan mengetahui objek yang hendak dijalankan. Dalam kes ini thisadalah rujukan kepada CounterThread. Setelah utas dibuat, ia perlu dimulakan. Panggilan ke start()akan memanggil kaedah sasaran run(), iaitu CounterThread. run(). Panggilan ke start()akan kembali serta-merta dan utas akan mula dijalankan pada masa yang sama. Perhatikan bahawa run()kaedahnya adalah gelung tanpa batas. Ia tidak terbatas kerana sekalirun()kaedah keluar, utas berhenti dijalankan. The run()kaedah akan kenaikan Count berubah-ubah, tidur selama 10 milisaat dan menghantar permintaan untuk menyegarkan paparan aplet ini.

Note that it is important to sleep somewhere in a thread. If not, the thread will consume all CPU time for the process and will not allow any other methods such as threads to be executed. Another way to cease the execution of a thread is to call the stop() method. In this example, the thread stops when the mouse is pressed while the cursor is in the applet. Depending on the speed of the computer the applet runs on, not every number will be displayed, because the incrementing is done independent of the painting of the applet. The applet can not be refreshed at every request, so the OS will queue the requests and successive refresh requests will be satisfied with one refresh. While the refreshes are queuing up, the Count is still being incremented but not displayed.

Suspending and resuming

Once a thread is stopped, it cannot be restarted with the start() command, since stop() will terminate the execution of a thread. Instead you can pause the execution of a thread with the sleep() method. The thread will sleep for a certain period of time and then begin executing when the time limit is reached. But, this is not ideal if the thread needs to be started when a certain event occurs. In this case, the suspend() method allows a thread to temporarily cease executing and the resume() method allows the suspended thread to start again. The following applet shows the above example modified to suspend and resume the applet.

public class CounterThread2 extends Applet implements Runnable { Thread t; int Count; boolean suspended; public boolean mouseDown(Event e,int x, int y) { if(suspended) t.resume(); else t.suspend(); suspended = !suspended; return true; } ... }

CounterThread2 Example and Source code

Untuk mengesan keadaan applet semasa, pemboleh ubah boolean suspendeddigunakan. Membezakan keadaan applet yang berbeza adalah penting kerana beberapa kaedah akan memberikan pengecualian jika disebut semasa berada dalam keadaan yang salah. Sebagai contoh, jika applet telah dimulakan dan dihentikan, menjalankan start()kaedah akan membuang IllegalThreadStateExceptionpengecualian.