Pengantar utas Java

Artikel ini, salah satu yang pertama diterbitkan oleh JavaWorld, menjelaskan bagaimana utas diterapkan dalam bahasa pemrograman Java, dimulai dengan gambaran umum utas.

Sederhananya, utas adalah jalur eksekusi program. Sebagian besar program yang ditulis hari ini berjalan sebagai utas tunggal, menyebabkan masalah saat banyak kejadian atau tindakan perlu terjadi pada waktu yang sama. Katakanlah, misalnya, sebuah program tidak mampu menggambar sambil membaca penekanan tombol. Program harus memberikan perhatian penuh pada masukan keyboard yang tidak memiliki kemampuan untuk menangani lebih dari satu peristiwa dalam satu waktu. Solusi ideal untuk masalah ini adalah eksekusi yang mulus dari dua atau lebih bagian program pada waktu yang bersamaan. Thread memungkinkan kita melakukan ini.

Mempelajari tentang utas Java

Artikel ini adalah bagian dari arsip konten teknis JavaWorld. Lihat yang berikut ini untuk mempelajari lebih lanjut tentang thread dan konkurensi Java:

Memahami utas Java ( seri Java 101 , 2002):

  • Bagian 1: Memperkenalkan utas dan runnable
  • Bagian 2: Sinkronisasi benang
  • Bagian 3: Penjadwalan utas dan tunggu / beri tahu
  • Bagian 4: Grup thread dan volatilitas

Artikel terkait

  • Hyper-threaded Java: Menggunakan Java Concurrency API (2006)
  • Monitor yang lebih baik untuk program multithread (2007)
  • Memahami konkurensi Aktor, Bagian 1 (2009)
  • Deteksi dan penanganan benang gantung (2011)

Periksa juga peta situs JavaWorld dan mesin pencari .

Aplikasi multithreaded memberikan kekuatannya yang kuat dengan menjalankan banyak thread secara bersamaan dalam satu program. Dari sudut pandang logis, multithreading berarti banyak baris dari satu program dapat dieksekusi pada saat yang sama, namun, ini tidak sama dengan memulai program dua kali dan mengatakan bahwa ada banyak baris program yang dijalankan pada saat yang sama waktu. Dalam hal ini, sistem operasi memperlakukan program sebagai dua proses yang terpisah dan berbeda. Di bawah Unix, forking sebuah proses membuat proses anak dengan ruang alamat berbeda untuk kode dan data. Namun,fork()menciptakan banyak biaya tambahan untuk sistem operasi, menjadikannya operasi yang sangat intensif CPU. Dengan memulai utas, jalur eksekusi yang efisien dibuat sambil tetap berbagi area data asli dari induk. Ide berbagi area data sangat bermanfaat, tetapi memunculkan beberapa area perhatian yang akan kita diskusikan nanti.

Membuat utas

Pembuat Java dengan anggun merancang dua cara membuat utas: mengimplementasikan antarmuka dan memperluas kelas. Memperluas kelas adalah cara Java mewarisi metode dan variabel dari kelas induk. Dalam kasus ini, seseorang hanya dapat memperluas atau mewarisi dari satu kelas induk. Batasan dalam Java ini dapat diatasi dengan mengimplementasikan antarmuka, yang merupakan cara paling umum untuk membuat utas. (Perhatikan bahwa tindakan mewarisi hanya memungkinkan kelas dijalankan sebagai utas. Terserah kelas untuk start()dieksekusi, dll.)

Antarmuka menyediakan cara bagi pemrogram untuk meletakkan dasar kelas. Mereka digunakan untuk mendesain persyaratan untuk sekumpulan kelas yang akan diimplementasikan. Antarmuka menyiapkan semuanya, dan kelas atau kelas yang mengimplementasikan antarmuka melakukan semua pekerjaan. Kumpulan kelas yang berbeda yang mengimplementasikan antarmuka harus mengikuti aturan yang sama.

Ada beberapa perbedaan antara kelas dan antarmuka. Pertama, antarmuka hanya dapat berisi metode abstrak dan / atau variabel akhir statis (konstanta). Kelas, di sisi lain, dapat mengimplementasikan metode dan berisi variabel yang bukan konstanta. Kedua, antarmuka tidak dapat mengimplementasikan metode apa pun. Kelas yang mengimplementasikan antarmuka harus mengimplementasikan semua metode yang ditentukan dalam antarmuka itu. Antarmuka memiliki kemampuan untuk diperluas dari antarmuka lain, dan (tidak seperti kelas) dapat diperluas dari beberapa antarmuka. Lebih lanjut, sebuah antarmuka tidak dapat dibuat dengan operator baru; misalnya Runnable a=new Runnable();tidak diperbolehkan.

Metode pertama untuk membuat utas adalah dengan memperluas dari Threadkelas. Lakukan ini hanya jika kelas yang Anda perlukan dijalankan sebagai utas tidak perlu diperpanjang dari kelas lain. The Threadkelas didefinisikan dalam paket java.lang, yang perlu diimpor sehingga kelas kami sadar definisi.

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

Contoh di atas membuat kelas baru Counteryang memperluas Threadkelas dan mengganti Thread.run()metode untuk implementasinya sendiri. The run()Metode adalah di mana semua pekerjaan Counterbenang kelas dilakukan. Kelas yang sama dapat dibuat dengan mengimplementasikan Runnable:

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

Di sini, run()metode abstrak didefinisikan di antarmuka Runnable dan sedang diterapkan. Perhatikan bahwa kita memiliki instance Threadkelas sebagai variabel Counterkelas. Satu-satunya perbedaan antara kedua metode tersebut adalah dengan mengimplementasikan Runnable, ada fleksibilitas yang lebih besar dalam pembuatan kelas Counter. Dalam contoh di atas, masih ada peluang untuk memperluas Counterkelas, jika diperlukan. Mayoritas kelas yang dibuat dan perlu dijalankan sebagai utas akan mengimplementasikan Runnable karena mereka mungkin memperluas beberapa fungsionalitas lain dari kelas lain.

Jangan berpikir bahwa antarmuka Runnable sedang melakukan pekerjaan nyata saat utas sedang dijalankan. Ini hanyalah sebuah kelas yang dibuat untuk memberikan gambaran tentang desain Threadkelas. Faktanya, sangat kecil hanya berisi satu metode abstrak. Berikut adalah definisi antarmuka Runnable langsung dari sumber Java:

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

Hanya itu yang ada di antarmuka Runnable. Antarmuka hanya menyediakan desain kelas yang harus diimplementasikan. Dalam kasus antarmuka Runnable, itu memaksa definisi hanya run()metode. Oleh karena itu, sebagian besar pekerjaan dilakukan di Threadkelas. Melihat lebih dekat pada bagian dalam definisi Threadkelas akan memberikan gambaran tentang apa yang sebenarnya terjadi:

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

Dari potongan kode di atas terbukti bahwa kelas Thread juga mengimplementasikan antarmuka Runnable. Thread. run()memeriksa untuk memastikan bahwa kelas target (kelas yang akan dijalankan sebagai utas) tidak sama dengan null, dan kemudian mengeksekusi run()metode target. Jika ini terjadi, run()metode target akan dijalankan sebagai utasnya sendiri.

Memulai dan menghentikan

Karena cara yang berbeda untuk membuat sebuah instance dari sebuah thread sekarang sudah jelas, kita akan membahas implementasi thread yang dimulai dengan cara yang tersedia untuk memulai dan menghentikannya menggunakan applet kecil yang berisi thread untuk mengilustrasikan mekanisme:

Contoh CounterThread dan Kode Sumber

Applet di atas akan mulai menghitung dari 0 yang menampilkan outputnya ke layar dan konsol. Sekilas mungkin memberi kesan bahwa program akan mulai menghitung dan menampilkan setiap angka, tetapi ini tidak terjadi. Pemeriksaan lebih dekat terhadap pelaksanaan applet ini akan mengungkapkan identitas aslinya.

Dalam kasus ini, CounterThreadkelas tersebut dipaksa untuk mengimplementasikan Runnable karena kelas tersebut memperluas Applet. Seperti di semua applet, init()metode ini dijalankan terlebih dahulu. Di init(), variabel Hitung diinisialisasi ke nol dan instance baru Threadkelas dibuat. Dengan meneruskan thiske Threadkonstruktor, utas baru akan mengetahui objek mana yang akan dijalankan. Dalam hal ini thisadalah referensi CounterThread. Setelah utas dibuat, utas harus dimulai. Panggilan ke start()akan memanggil metode target run(), yaitu CounterThread. run(). Panggilan ke start()akan langsung kembali dan utas akan mulai dijalankan pada saat yang bersamaan. Perhatikan bahwa run()metode ini adalah pengulangan tanpa batas. Itu tidak terbatas karena sekalirun()metode keluar, utas berhenti mengeksekusi. The run()Metode akan kenaikan Count variabel, tidur selama 10 milidetik dan mengirim permintaan untuk me-refresh tampilan applet.

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 melacak status applet saat ini, variabel boolean suspendeddigunakan. Membedakan status applet yang berbeda adalah penting karena beberapa metode akan mengeluarkan pengecualian jika dipanggil saat berada dalam status yang salah. Misalnya, jika applet telah dimulai dan dihentikan, menjalankan start()metode ini akan memunculkan IllegalThreadStateExceptionpengecualian.