Siklus Hidup Thread di Java

1. Perkenalan

Dalam artikel ini, kita akan membahas secara detail konsep inti di Java - siklus hidup sebuah utas.

Kami akan menggunakan diagram bergambar cepat dan, tentu saja, cuplikan kode praktis untuk lebih memahami status ini selama eksekusi utas.

Untuk mulai memahami Thread di Java, artikel tentang membuat thread ini adalah tempat yang baik untuk memulai.

2. Multithreading di Java

Dalam bahasa Java, multithreading didorong oleh konsep inti Thread . Selama siklus hidupnya, utas melewati berbagai status:

3. Siklus Hidup Thread di Jawa

Kelas java.lang.Thread berisi enum Status statis - yang mendefinisikan status potensinya. Selama titik waktu tertentu, utas hanya dapat berada di salah satu status berikut:

  1. BARU - utas yang baru dibuat yang belum memulai eksekusi
  2. DAPAT DIJALANKAN - sedang berjalan atau siap untuk dieksekusi tetapi menunggu alokasi sumber daya
  3. DIBLOKIR - menunggu untuk mendapatkan kunci monitor untuk memasuki atau memasukkan kembali blok / metode yang disinkronkan
  4. MENUNGGU - menunggu utas lain untuk melakukan tindakan tertentu tanpa batas waktu
  5. TIMED_WAITING - menunggu utas lain melakukan tindakan tertentu untuk jangka waktu tertentu
  6. TERMINATED - telah menyelesaikan eksekusinya

Semua status ini tercakup dalam diagram di atas; sekarang mari kita bahas masing-masing secara rinci.

3.1. Baru

Sebuah NEW Thread (atau Born Thread ) adalah benang yang telah dibuat tetapi belum mulai. Ini tetap dalam keadaan ini sampai kita memulainya menggunakan metode start () .

Cuplikan kode berikut menunjukkan utas yang baru dibuat dalam status BARU :

Runnable runnable = new NewState(); Thread t = new Thread(runnable); Log.info(t.getState());

Karena kita belum memulai utas yang disebutkan, metode t.getState () mencetak:

NEW

3.2. Dapat dijalankan

Ketika kita telah membuat utas baru dan memanggil metode start () , itu dipindahkan dari status BARU ke RUNNABLE . Utas dalam status ini sedang berjalan atau siap dijalankan, tetapi mereka menunggu alokasi sumber daya dari sistem.

Dalam lingkungan multi-threaded, Thread-Scheduler (yang merupakan bagian dari JVM) mengalokasikan jumlah waktu yang tetap untuk setiap thread. Jadi, ini berjalan untuk jangka waktu tertentu, lalu melepaskan kontrol ke utas yang DAPAT DIJALANKAN .

Sebagai contoh, mari tambahkan metode t.start () ke kode sebelumnya dan coba akses statusnya saat ini:

Runnable runnable = new NewState(); Thread t = new Thread(runnable); t.start(); Log.info(t.getState());

Kode ini kemungkinan besar menampilkan keluaran sebagai:

RUNNABLE

Perhatikan bahwa dalam contoh ini, tidak selalu dijamin bahwa pada saat kontrol kita mencapai t.getState () , itu akan tetap dalam status RUNNABLE .

Mungkin terjadi bahwa itu segera dijadwalkan oleh Thread-Scheduler dan dapat menyelesaikan eksekusi. Dalam kasus seperti itu, kami mungkin mendapatkan hasil yang berbeda.

3.3. Diblokir

Sebuah utas dalam status DIBLOKIR jika saat ini tidak memenuhi syarat untuk dijalankan. Ini memasuki keadaan ini ketika menunggu kunci monitor dan mencoba mengakses bagian kode yang dikunci oleh utas lain.

Mari kita coba mereproduksi keadaan ini:

public class BlockedState { public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(new DemoThreadB()); Thread t2 = new Thread(new DemoThreadB()); t1.start(); t2.start(); Thread.sleep(1000); Log.info(t2.getState()); System.exit(0); } } class DemoThreadB implements Runnable { @Override public void run() { commonResource(); } public static synchronized void commonResource() { while(true) { // Infinite loop to mimic heavy processing // 't1' won't leave this method // when 't2' try to enter this } } }

Dalam kode ini:

  1. Kami telah membuat dua utas berbeda - t1 dan t2
  2. t1 memulai dan memasukkan metode commonResource () tersinkronisasi ; ini berarti hanya satu utas yang dapat mengaksesnya; semua utas berikutnya yang mencoba mengakses metode ini akan diblokir dari eksekusi lebih lanjut hingga utas saat ini menyelesaikan pemrosesan
  3. Ketika t1 memasuki metode ini, ia disimpan dalam while loop yang tak terbatas; ini hanya untuk meniru pemrosesan yang berat sehingga semua utas lainnya tidak dapat masuk ke metode ini
  4. Sekarang ketika kita mulai t2 , mencoba untuk memasuki commonResource () metode, yang sudah sedang diakses oleh t1, dengan demikian, t2 akan disimpan di DIBLOKIR negara

Berada dalam keadaan ini, kita memanggil t2.getState () dan mendapatkan keluaran sebagai:

BLOCKED

3.4. Menunggu

Sebuah utas berada dalam status MENUNGGU ketika sedang menunggu utas lain untuk melakukan tindakan tertentu. Menurut JavaDocs, utas apa pun dapat memasuki status ini dengan memanggil salah satu dari tiga metode berikut:

  1. object.wait ()
  2. thread.join () atau
  3. LockSupport.park ()

Perhatikan bahwa di wait () dan join () - kami tidak menentukan periode waktu tunggu karena skenario tersebut dibahas di bagian selanjutnya.

Kami memiliki tutorial terpisah yang membahas secara rinci penggunaan wait () , notify () dan notifyAll () .

Untuk saat ini, mari kita coba mereproduksi keadaan ini:

public class WaitingState implements Runnable { public static Thread t1; public static void main(String[] args) { t1 = new Thread(new WaitingState()); t1.start(); } public void run() { Thread t2 = new Thread(new DemoThreadWS()); t2.start(); try { t2.join(); } catch (InterruptedException e) { Thread.currentThread().interrupt(); Log.error("Thread interrupted", e); } } } class DemoThreadWS implements Runnable { public void run() { try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); Log.error("Thread interrupted", e); } Log.info(WaitingState.t1.getState()); } }

Let's discuss what we're doing here:

  1. We've created and started the t1
  2. t1 creates a t2 and starts it
  3. While the processing of t2 continues, we call t2.join(), this puts t1 in WAITING state until t2 has finished execution
  4. Since t1 is waiting for t2 to complete, we're calling t1.getState() from t2

The output here is, as you'd expect:

WAITING

3.5. Timed Waiting

A thread is in TIMED_WAITING state when it's waiting for another thread to perform a particular action within a stipulated amount of time.

According to JavaDocs, there are five ways to put a thread on TIMED_WAITING state:

  1. thread.sleep(long millis)
  2. wait(int timeout) or wait(int timeout, int nanos)
  3. thread.join(long millis)
  4. LockSupport.parkNanos
  5. LockSupport.parkUntil

To read more about the differences between wait() and sleep() in Java, have a look at this dedicated article here.

For now, let's try to quickly reproduce this state:

public class TimedWaitingState { public static void main(String[] args) throws InterruptedException { DemoThread obj1 = new DemoThread(); Thread t1 = new Thread(obj1); t1.start(); // The following sleep will give enough time for ThreadScheduler // to start processing of thread t1 Thread.sleep(1000); Log.info(t1.getState()); } } class DemoThread implements Runnable { @Override public void run() { try { Thread.sleep(5000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); Log.error("Thread interrupted", e); } } }

Here, we've created and started a thread t1 which is entered into the sleep state with a timeout period of 5 seconds; the output will be:

TIMED_WAITING

3.6. Terminated

This is the state of a dead thread. It's in the TERMINATED state when it has either finished execution or was terminated abnormally.

We have a dedicated article that discusses different ways of stopping the thread.

Let's try to achieve this state in the following example:

public class TerminatedState implements Runnable { public static void main(String[] args) throws InterruptedException { Thread t1 = new Thread(new TerminatedState()); t1.start(); // The following sleep method will give enough time for // thread t1 to complete Thread.sleep(1000); Log.info(t1.getState()); } @Override public void run() { // No processing in this block } }

Here, while we've started thread t1, the very next statement Thread.sleep(1000) gives enough time for t1 to complete and so this program gives us the output as:

TERMINATED

In addition to the thread state, we can check the isAlive() method to determine if the thread is alive or not. For instance, if we call the isAlive() method on this thread:

Assert.assertFalse(t1.isAlive());

Ini mengembalikan false. Sederhananya, utas hidup jika dan hanya jika telah dimulai dan belum mati.

4. Kesimpulan

Dalam tutorial ini, kita belajar tentang siklus hidup utas di Java. Kami melihat keenam status yang ditentukan oleh enum Thread.State dan mereproduksinya dengan contoh cepat.

Meskipun cuplikan kode akan memberikan keluaran yang sama di hampir setiap mesin, dalam beberapa kasus luar biasa, kami mungkin mendapatkan beberapa keluaran yang berbeda karena perilaku Penjadwal Utas yang tepat tidak dapat ditentukan.

Dan, seperti biasa, potongan kode yang digunakan di sini tersedia di GitHub.