ว่าด้วยเรื่อง “วงจรชีวิตของ Thread” ใน Java

Phayao Boonon
4 min readOct 3, 2018

--

สำหรับเรื่อง Concurrency ใน Java นั้น Thread เป็นส่วนสำคัญมาก แต่ก็อาจจะมีคนสงสัยว่า “วงจรชีวิต” ของ Thread นั้นมันเป็นอย่างไรกันน๊าาา บทความนี้จึงจะมาพูดถึงวงจรชีวิตของ Thread ในภาษา Java กันครับ

เรามาเริ่มต้นกับรูปของวงจรชีวิตของ Thread กันว่าตั้งแต่เกิดจนตายนั้นเป็นอย่างไร

สถานะของ Thread

คลาส java.lang.Thread จะระบุสถานะของ thread ด้วย enum ชื่อว่า State ซึ่งเป็นค่าที่บอกว่าตอนนี้ thread มีสถานะเป็นอะไร ดังนี้

  • NEW — สถานะตอนสร้าง Thread ใหม่เลยและยังไม่ให้ thread เริ่มทำงาน
  • RUNNABLE — สถานะของทั้งกำลังทำงานอยู่ (running) หรือพร้อมที่จะทำงาน (ready) แล้วแต่ไม่ใช่สถานะตอนรอทรัพยากรของระบบ
  • BLOCKED — สถานะที่ถูกล็อกเพื่อจะเข้าสู่ synchronized block/method
  • WAITING — สถานะที่รอ thread อื่นทำงานบางอย่างให้เสร็จก่อนโดยไม่ได้จำกัดระยะเวลาว่าให้ thread นั้นทำงานนานเท่าไร
  • TIMED_WAITING — สถานะที่รอ thread อื่นทำงานบางอย่างให้เสร็จก่อนโดยที่ระบุระยะเวลาว่าให้ thread อื่นทำงานนานเท่าไร
  • TERMINATED — สถานะที่ thread นั้นทำงานเรียบร้อยแล้ว

ซึ่งต่อไปจะมาดูรายละเอียดของแต่ละสถานะว่าทำงานอย่างไร

New

เป็นขั้นตอนการสร้าง thread ใหม่ ซึ่ง thread จะถูกสร้างแต่ยังไม่ได้เริ่มทำงาน ซึ่งมันจะยังคงสถานะนี้จนกว่า method start() จะถูกเรียก

สามารถสร้าง thread t ได้ด้วย keyword new คลาส Thread ซึ่งรับ argument เป็นคลาส Runnable ซึ่งคลาส HelloRunnable ได้ implement interface Runnable แล้วถือว่าเป็น type เดียวกัน และตรวจสอบสถานะของ thread t ด้วย getState() จะได้สถานะเป็น NEW

public class HelloThread {
public static void main(String[] args) {
Thread t = new Thread(new HelloRunnable());

System.out.println(t.getState());
}
}

class HelloRunnable implements Runnable {
@Override
public void run() {
}
}

แสดงสถานะของ thread t ดัวย method getState()

NEW

Runnable

เมื่อเราสร้าง thread และ call method start() ก็จะเปลี่ยนสถานะจาก NEW ไปเป็น RUNNABLE เป็นสถานะของทั้งกำลังทำงานอยู่ (running) หรือพร้อมที่จะทำงาน (ready) แล้วแต่ไม่ใช่สถานะตอนรอทรัพยากรของระบบ

ใน multi-threaded environment, Thread-Scheduler ซึ่งเป็นส่วนหนึ่งของ JVM จะอนุญาตช่วงเวลาหนึ่งสำหรับแต่ละ thread ดังนั้นมันจะทำงานในช่วงเวลาในเวลาหนึ่งมากกว่าที่ปล่อยให้ความคุม RUNNABLE thread อื่น

สามารถรัน thread ได้ด้วยการใช้ method start() ดังนี้

public class HelloThread {
public static void main(String[] args) {
Thread t = new Thread(new HelloRunnable());

t.start();

System.out.println(t.getState());
}
}

class HelloRunnable implements Runnable {
@Override
public void run() {
}
}

แสดงสถานะของ thread ดัวย method getState()

RUNNABLE

Blocked

Thread จะมีสถานะเป็น BLOCKED ก็ต่อเมื่อมันไม่มีสิทธิทำงาน ซึ่งมันจะเข้าสู่สถานะนี้เมื่อรอสำหรับ monitor lock และพยายาม access เข้าไปหาโค้ดที่ถูกล็อกด้วย thread อื่น

โดยโค้ดตัวอย่างทำงานด้วยการสร้าง thread มา 2 ตัวคือ t1 และ t2 ด้วยคลาส HelloRunnable ซึ่ง มี synchronize method ที่เหมือนเป็นทรัพยากรร่วมกันและทำงาน infinity และให้เทรดทั้งสองทำงานด้วย t1.start() และ t2.start() หลังจากนั้น sleep main thread 1 วินาที และตรวจสอบสถานะ t1 เป็น RUNNABLE และสถานะของ t2 เป็น BLOCKED เพราะว่า thread t1 ทำงานและเรียก synchronize method ที่ใช้ทรัพยากรร่วมอยู่ (ซึ่ง while(true) คือทำงานตลอดไป) ดังนั้น thread t2 จึงอยู่ในสถานะ BLOCKED เพราะพยายามใช้ทรัพยากรร่วม

public class HelloThread {
public static void main(String[] args) throws InterruptedException {
Thread t1 = new Thread(new HelloRunnable());
Thread t2 = new Thread(new HelloRunnable());

t1.start();
t2.start();

Thread.sleep(1000);
System.out.println(t1.getState());
System.out.println(t2.getState());
}
}

class HelloRunnable implements Runnable {
@Override
public void run() {
commonResource();
}

public static synchronized void commonResource() {
while (true); // Infinity loop
}
}

จะได้ผลลัพธ์ดังนี้

RUNNABLE
BLOCKED

Waiting

Thread จะมีสถานะเป็น WAITING ก็ต่อเมื่อมันรอ thread อื่นทำงานบางอย่างให้เสร็จก่อน ซึ่ง thread สามารถเข้าสู่สถานะนี้ได้ถ้าเรียก method เหล่านี้

  • Object.wait ไม่ต้องมี timeout
  • thread.join ไม่ต้องมี timeout
  • LockSupport.park

โดยโค้ดตังอย่างทำงานดังนี้

  1. สร้าง thread t1 ใน HelloThread ที่ implement interface Runnable และให้ thread t1 ทำงานด้วย start()
  2. ใน method run() ของ thread t1 สร้าง thread t2 และให้ thread t2 ทำงาน หลังจากนั้น call t2.joint() เพื่อให้ thread t1 อยู่ในสถานะ WAITING เพื่อให้ thread t2 ทำงานเสร็จก่อนโดยไม่กำหนดเวลา
  3. โดยใน thread t2 ทำงานตรวจสอบสถานะของ thread t1 ด้วย getState() แสดงบนหน้าจอ
public class HelloThread implements Runnable {
public static Thread t1;
public static void main(String[] args) throws InterruptedException {
t1 = new Thread(new HelloThread());
t1.start();
}

@Override
public void run() {
Thread t2 = new Thread(new HelloRunnable());
t2.start();

try {
t2.join();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("Thread is interrupted");
}
}
}

class HelloRunnable implements Runnable {
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("Thread interrupted");
}

System.out.println(HelloThread.t.getState());
}
}

จะได้ผลลัพธ์ดังนี้

WAITING

Timed Waiting

Thread จะมีสถานะเป็น TIMED_WAITING ก็ต่อเมื่อ thread รอให้ thread อื่นทำงานบางอย่างโดยระบุเวลา ซึ่ง thread สามมารถเข้าสู่สถานะนี้ได้ถ้าเรียก method เหล่านี้

  • Thread.sleep
  • Object.wait มี timeout
  • Thread.join มี timeout
  • LockSupport.partNanos
  • LockSupport.partUntil

โดยโค้ดตัวอย่างทำงานด้วยการสร้าง thread t และให้ทำงานด้วย start() ซึ่งใน thread t1 จะเรียก Thread.sleep() เพื่อหยุดดการทำงานของ thread เวลา 5 วินาที และใน main thread ก็ตรวจสอบสถานะของ thread t1 จะเห็นได้ว่ามีสถานะ TIMED_WAITING ซึ่งเป็นผลมาจาก thread t1 เรียก sleep()

public class HelloThread {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new HelloRunnable());

t.start();

Thread.sleep(1000);
System.out.println(t.getState());
}
}

class HelloRunnable implements Runnable {
@Override
public void run() {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
System.out.println("Thread interrupted");
}
}
}

จะได้ผลลัยธ์ดังนี่

TIMED_WAITING

Terminate

สถานะนี้เป็นสถานะที่ thread หยุดการทำงาน ซึ่งสถานะ TERMINATED เมื่อ thread หยุดการทำงานหรือถูกยุติการทำงาน

โดยโค้ดตัวอย่างทำงานง่ายมากด้วยการสร้าง thread t และให้ thread t ทำงานด้วย start() และหยุด main thread 1 วินาที แล้วมาตรวจสอบสถานะของ thread t จะเห็นได้ว่า thread ทำงานเสร็จแล้วมีสถานะเป็น TERMINATED

public class HelloThread {
public static void main(String[] args) throws InterruptedException {
Thread t = new Thread(new HelloRunnable());
t.start();

Thread.sleep(1000);
System.out.println(t.getState());
}
}

class HelloRunnable implements Runnable {
@Override
public void run() {
}
}

จะได้ผลลัพธ์ดังนี้

TERMINATED

อ้างอิง

--

--

Phayao Boonon
Phayao Boonon

Written by Phayao Boonon

Software Engineer 👨🏻‍💻 Stay Hungry Stay Foolish

No responses yet