Kitaran Hidup Benang di Jawa

1. Pengenalan

Dalam artikel ini, kita akan membincangkan secara terperinci konsep teras di Java - kitaran hidup utas.

Kami akan menggunakan gambar rajah cepat dan, tentu saja, coretan kod praktikal untuk lebih memahami keadaan ini semasa pelaksanaan utas.

Untuk mula memahami Threads di Java, artikel ini untuk membuat utas adalah tempat yang baik untuk memulakan.

2. Multithreading di Jawa

Dalam bahasa Java, multithreading didorong oleh konsep teras Thread . Semasa kitaran hidup mereka, utas melalui pelbagai keadaan:

3. Kitaran Hidup Benang di Jawa

The java.lang.Thread kelas mengandungi statik Negeri enum - yang mentakrifkan negeri potensinya. Dalam jangka masa tertentu, utas hanya boleh berada di salah satu keadaan berikut:

  1. BARU - utas yang baru dibuat yang belum memulakan pelaksanaan
  2. DIJALANKAN - sama ada berjalan atau siap untuk dilaksanakan tetapi menunggu peruntukan sumber
  3. DITUKAR - menunggu untuk mendapatkan kunci monitor untuk memasuki atau memasukkan semula blok / kaedah yang disegerakkan
  4. MENUNGGU - menunggu beberapa utas lain melakukan tindakan tertentu tanpa had masa
  5. TIMED_WAITING - menunggu beberapa utas lain melakukan tindakan tertentu untuk jangka masa yang ditentukan
  6. TERMINAT - telah menyelesaikan pelaksanaannya

Semua keadaan ini diliputi dalam rajah di atas; mari kita bincangkan setiap perkara ini secara terperinci.

3.1. Baru

A NEW Thread (atau Born Thread ) adalah thread yang telah dibuat tetapi belum bermula. Ia tetap dalam keadaan ini sehingga kita memulakannya menggunakan kaedah start () .

Coretan kod berikut menunjukkan utas yang baru dibuat yang berada dalam keadaan BARU :

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

Oleh kerana kami belum memulakan utas yang disebutkan, kaedah t.getState () mencetak:

NEW

3.2. Boleh dijalankan

Apabila kami telah membuat thread baru dan memanggil kaedah start () , ia dipindahkan dari keadaan BARU ke RUNNABLE . Thread dalam keadaan ini berjalan atau siap untuk dijalankan, tetapi mereka sedang menunggu peruntukan sumber dari sistem.

Dalam persekitaran pelbagai utas, Thread-Penjadual (yang merupakan sebahagian daripada JVM) memperuntukkan jumlah masa yang tetap untuk setiap utas. Oleh itu, ia berjalan untuk jangka masa tertentu, kemudian melepaskan kawalan ke utas RUNNABLE yang lain .

Sebagai contoh, mari kita tambahkan kaedah t.start () ke kod sebelumnya dan cuba mengakses keadaannya sekarang:

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

Kod ini kemungkinan besar akan mengembalikan output sebagai:

RUNNABLE

Perhatikan bahawa dalam contoh ini, tidak selalu dijamin bahawa pada saat kawalan kita mencapai t.getState () , ia masih dalam keadaan BERJALAN .

Mungkin berlaku bahawa ia segera dijadwalkan oleh Thread-Penjadual dan mungkin selesai pelaksanaan. Dalam kes seperti itu, kita mungkin mendapat output yang berbeza.

3.3. Dihalang

Suatu utas dalam keadaan DITOLAK saat ini tidak layak dijalankan. Ia memasuki keadaan ini ketika menunggu kunci monitor dan berusaha mengakses bahagian kod yang dikunci oleh beberapa utas lain.

Mari cuba menghasilkan semula 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 kod ini:

  1. Kami telah mencipta dua utas yang berbeza - t1 dan t2
  2. t1 memulakan dan memasuki kaedah commonResource () yang diselaraskan ; ini bermaksud hanya satu utas yang dapat mengaksesnya; semua utas berikutnya yang cuba mengakses kaedah ini akan disekat dari pelaksanaan selanjutnya sehingga yang terakhir akan menyelesaikan pemprosesan
  3. Apabila t1 memasuki kaedah ini, ia disimpan dalam gelung sementara tanpa had; ini hanya untuk meniru pemprosesan yang berat sehingga semua utas lain tidak dapat memasuki kaedah ini
  4. Sekarang apabila kita mula t2 , ia cuba untuk memasuki commonResource () kaedah, yang sudah diakses oleh t1, dengan itu, t2 akan disimpan dalam DISEKAT negeri

Berada dalam keadaan ini, kami memanggil t2.getState () dan mendapatkan output sebagai:

BLOCKED

3.4. Menunggu

Benang dalam keadaan MENUNGGU ketika sedang menunggu beberapa utas lain untuk melakukan tindakan tertentu. Menurut JavaDocs, sebarang utas dapat memasuki keadaan ini dengan memanggil salah satu dari tiga kaedah berikut:

  1. objek. tunggu ()
  2. utas.join () atau
  3. LockSupport.park ()

Perhatikan bahawa dalam menunggu () dan bergabung () - kami tidak menentukan jangka masa tamat kerana senario tersebut akan dibahas di bahagian seterusnya.

Kami mempunyai tutorial berasingan yang membincangkan secara terperinci penggunaan tunggu () , memberitahu () dan notifikasiSemua () .

Buat masa ini, mari cuba menghasilkan semula 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());

Ia kembali palsu. Ringkasnya, benang hidup jika dan hanya jika ia telah dimulakan dan belum mati.

4. Kesimpulan

Dalam tutorial ini, kami belajar mengenai kitaran hidup utas di Java. Kami melihat keenam-enam keadaan yang ditentukan oleh Thread.State enum dan menghasilkannya semula dengan contoh cepat.

Walaupun coretan kod akan memberikan output yang sama di hampir setiap mesin, dalam beberapa kes yang luar biasa, kami mungkin mendapat beberapa output yang berbeza kerana tingkah laku Thread Scheduler yang tepat tidak dapat ditentukan.

Dan, seperti biasa, coretan kod yang digunakan di sini terdapat di GitHub.