มัลติเธรดใน Java


แอปพลิเคชันใดๆ ก็สามารถมีกระบวนการ (อินสแตนซ์) ได้หลายกระบวนการ โดยแต่ละกระบวนการสามารถกำหนดให้เป็นเธรดเดียวหรือหลายเธรดก็ได้ ในบทช่วยสอนนี้ เราจะมาดูวิธีการทำงานหลายงานพร้อมกัน และเรียนรู้เพิ่มเติมเกี่ยวกับเธรดและการซิงโครไนซ์ระหว่างเธรด

เธรดเดี่ยวคืออะไร?

ด้ายเส้นเดียวเข้า. Java โดยพื้นฐานแล้วเป็นหน่วยการประมวลผลที่มีน้ำหนักเบาและเป็นหน่วยที่เล็กที่สุด Java ใช้เธรดโดยใช้ “คลาสเธรด” มีเธรดสองประเภท – เธรดผู้ใช้และเธรด daemon (เธรดเดมอนใช้เมื่อเราต้องการทำความสะอาดแอปพลิเคชันและใช้ในเบื้องหลัง) เมื่อแอปพลิเคชันเริ่มทำงาน เธรดผู้ใช้จะถูกสร้างขึ้น หลังจากนั้น เราสามารถสร้างเธรดผู้ใช้และเธรดเดมอนได้หลายเธรด

ตัวอย่างเธรดเดี่ยว:

package demotest;

public class GuruThread
{
       public static void main(String[] args) {
              System.out.println("Single Thread");
       }
}

ข้อดีของเธรดเดี่ยว:

  • ลดค่าใช้จ่ายในแอปพลิเคชันเมื่อดำเนินการเธรดเดียวในระบบ
  • นอกจากนี้ยังช่วยลดต้นทุนการบำรุงรักษาแอปพลิเคชันอีกด้วย

มัลติเธรดคืออะไร Java?

มัลติเธรด in Java เป็นกระบวนการดำเนินการเธรดสองเธรดหรือมากกว่าพร้อมกันเพื่อให้ใช้ CPU ได้อย่างเต็มประสิทธิภาพ แอปพลิเคชันมัลติเธรดจะดำเนินการเธรดสองเธรดหรือมากกว่าพร้อมกัน ดังนั้นจึงเรียกอีกอย่างว่า Concurrency ใน Java- แต่ละเธรดทำงานขนานกัน เธรด Mulitple ไม่ได้จัดสรรพื้นที่หน่วยความจำแยกกัน ดังนั้นจึงช่วยประหยัดหน่วยความจำ นอกจากนี้ การสลับบริบทระหว่างเธรดใช้เวลาน้อยลง

ตัวอย่างของมัลติเธรด:

package demotest;
public class GuruThread1 implements Runnable
{
       public static void main(String[] args) {
        Thread guruThread1 = new Thread("Guru1");
        Thread guruThread2 = new Thread("Guru2");
        guruThread1.start();
        guruThread2.start();
        System.out.println("Thread names are following:");
        System.out.println(guruThread1.getName());
        System.out.println(guruThread2.getName());
    }
    @Override
    public void run() {
    }
}

ข้อดีของมัลติเธรด:

  • ผู้ใช้จะไม่ถูกบล็อคเนื่องจากเธรดเป็นอิสระ และเราสามารถดำเนินการหลายอย่างพร้อมกันได้
  • เนื่องจากเธรดนั้นมีความเป็นอิสระ เธรดอื่นจะไม่ได้รับผลกระทบหากเธรดหนึ่งตรงตามข้อยกเว้น

วงจรชีวิตของเธรดใน Java

วงจรชีวิตของเธรด:

วงจรชีวิตของเธรดใน Java
วงจรชีวิตของเธรดใน Java

วงจรชีวิตของเธรดมีระยะต่างๆ ดังแสดงในแผนภาพด้านบน:

  1. ใหม่
  2. รันได้
  3. เล่น
  4. ที่รอ
  5. ตาย
  1. ใหม่: ในขั้นตอนนี้ เธรดจะถูกสร้างขึ้นโดยใช้คลาส "คลาสเธรด" ซึ่งจะคงอยู่ในสถานะนี้จนกระทั่งโปรแกรม เริ่มต้น ด้าย เป็นที่รู้จักกันว่าด้ายเกิด
  2. รันได้: ในหน้านี้ อินสแตนซ์ของเธรดถูกเรียกใช้ด้วยวิธีเริ่มต้น ตัวควบคุมเธรดถูกกำหนดให้กับตัวกำหนดเวลาเพื่อสิ้นสุดการดำเนินการ ขึ้นอยู่กับตัวกำหนดเวลาว่าจะรันเธรดหรือไม่
  3. เล่น: เมื่อเธรดเริ่มทำงาน สถานะจะเปลี่ยนเป็นสถานะ "กำลังทำงาน" ตัวกำหนดเวลาเลือกหนึ่งเธรดจากกลุ่มเธรด และเริ่มดำเนินการในแอปพลิเคชัน
  4. ที่รอ: นี่คือสถานะที่เธรดต้องรอ เนื่องจากมีเธรดหลายเธรดกำลังทำงานอยู่ในแอปพลิเคชัน จึงจำเป็นต้องซิงโครไนซ์ระหว่างเธรด ดังนั้น เธรดหนึ่งต้องรอจนกว่าเธรดอื่นจะดำเนินการได้ ดังนั้น สถานะนี้จึงเรียกว่าสถานะรอ
  5. ตาย: นี่คือสถานะเมื่อเธรดถูกยกเลิก เธรดอยู่ในสถานะกำลังทำงาน และทันทีที่ประมวลผลเสร็จสิ้น เธรดจะอยู่ใน "สถานะไม่ทำงาน"


วิธีการมัลติเธรดใน Java

วิธีการเธรดที่ใช้กันทั่วไปบางส่วน ได้แก่:

วิธี Descriptไอออน
เริ่ม () วิธีการนี้จะเริ่มต้นการดำเนินการของเธรดและ JVM เรียกเมธอด run() บนเธรด
นอนหลับ(int มิลลิวินาที) วิธีการนี้จะทำให้เธรดเข้าสู่โหมดพัก ดังนั้นการดำเนินการของเธรดจะหยุดชั่วคราวเป็นเวลาหลายมิลลิวินาที จากนั้นเธรดจะเริ่มทำงานอีกครั้ง ซึ่งจะช่วยในการซิงโครไนซ์เธรด
getName () มันจะส่งคืนชื่อของเธรด
setPriority (ลำดับความสำคัญใหม่ int) มันเปลี่ยนลำดับความสำคัญของเธรด
ผลผลิต () มันทำให้เธรดปัจจุบันหยุดทำงานและเธรดอื่น ๆ เพื่อดำเนินการ

ตัวอย่าง: ในโปรแกรมมัลติเธรดนี้ค่ะ Java ตัวอย่างเช่น เราจะสร้างเธรดและสำรวจวิธีการที่มีอยู่ภายในที่มีให้สำหรับเธรด

package demotest;
public class thread_example1 implements Runnable {
    @Override
    public void run() {
    }
    public static void main(String[] args) {
        Thread guruthread1 = new Thread();
        guruthread1.start();
        try {
            guruthread1.sleep(1000);
        } catch (InterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        guruthread1.setPriority(1);
        int gurupriority = guruthread1.getPriority();
        System.out.println(gurupriority);
        System.out.println("Thread Running");
  }
}

คำอธิบายของรหัส:

  • Code 2 แนว: เรากำลังสร้างคลาส “thread_Example1” ซึ่งใช้งานอินเทอร์เฟซ Runnable (ควรใช้งานโดยคลาสใดๆ ที่มีอินสแตนซ์ตั้งใจให้รันโดยเธรด)
  • Code 4 แนว: จะแทนที่วิธีการรันของอินเทอร์เฟซที่รันได้ เนื่องจากจำเป็นต้องแทนที่วิธีการนั้น
  • Code 6 แนว: ที่นี่เราได้กำหนดวิธีการหลักที่เราจะเริ่มต้นการทำงานของเธรด
  • Code 7 แนว: ที่นี่เรากำลังสร้างชื่อเธรดใหม่เป็น "guruthread1" โดยการสร้างคลาสของเธรดใหม่
  • Code 8 แนว: เราจะใช้วิธี "เริ่มต้น" ของเธรดโดยใช้อินสแตนซ์ "guruthread1" ที่นี่เธรดจะเริ่มดำเนินการ
  • Code 10 แนว: ที่นี่เราใช้วิธี "sleep" ของเธรดโดยใช้อินสแตนซ์ "guruthread1" ดังนั้น เธรดจะเข้าสู่โหมดสลีปเป็นเวลา 1000 มิลลิวินาที
  • Code 9-14: ที่นี่เราได้ใส่วิธี sleep ไว้ใน try catch block เนื่องจากมีการตรวจสอบข้อยกเว้นซึ่งเกิดขึ้น เช่น ข้อยกเว้นที่ถูกขัดจังหวะ
  • Code 15 แนว: ที่นี่เรากำลังตั้งค่าลำดับความสำคัญของเธรดเป็น 1 จากลำดับความสำคัญใดก็ตาม
  • Code 16 แนว: ที่นี่เราได้รับลำดับความสำคัญของเธรดโดยใช้ getPriority()
  • Code 17 แนว: ที่นี่เรากำลังพิมพ์ค่าที่ดึงมาจาก getPriority
  • Code 18 แนว: ที่นี่เรากำลังเขียนข้อความที่เธรดกำลังทำงานอยู่

เมื่อคุณรันโค้ดข้างต้น คุณจะได้ผลลัพธ์ต่อไปนี้:

ตัวอย่างกระทู้ใน Java

Output:

5 คือลำดับความสำคัญของเธรด และการรันเธรดคือข้อความซึ่งเป็นเอาต์พุตของโค้ดของเรา

Java ด้าย Syncการทำให้เป็นพงศาวดาร

ในการทำงานแบบมัลติเธรด โปรแกรมจะทำงานแบบอะซิงโครนัส หากเธรดหนึ่งเขียนข้อมูลบางอย่างและอีกเธรดหนึ่งอ่านข้อมูลในเวลาเดียวกัน อาจทำให้แอปพลิเคชันเกิดความไม่สอดคล้องกันได้ เมื่อจำเป็นต้องเข้าถึงทรัพยากรที่ใช้ร่วมกันโดยเธรดสองเธรดหรือมากกว่านั้น จะใช้แนวทางการซิงโครไนซ์ Java ได้จัดเตรียมวิธีการแบบซิงโครไนซ์เพื่อใช้ในการดำเนินงานลักษณะการทำงานแบบซิงโครไนซ์

ในแนวทางนี้ เมื่อเธรดเข้าไปถึงภายในบล็อกที่ซิงโครไนซ์แล้ว เธรดอื่นจะไม่สามารถเรียกใช้เมธอดนั้นในอ็อบเจ็กต์เดียวกันได้ เธรดทั้งหมดต้องรอจนกว่าเธรดนั้นจะเสร็จสิ้นบล็อกที่ซิงโครไนซ์และออกมาจากบล็อกนั้น ด้วยวิธีนี้ การซิงโครไนซ์จึงช่วยในแอปพลิเคชันแบบมัลติเธรด เธรดหนึ่งต้องรอจนกว่าเธรดอื่นจะเสร็จสิ้นการดำเนินการเท่านั้น จึงจะอนุญาตให้เธรดอื่นดำเนินการได้

สามารถเขียนได้ในรูปแบบต่อไปนี้:

Synchronized(object)
{  
        //Block of statements to be synchronized
}

มัลติเธรดใน Java ตัวอย่างโปรแกรม

ในมัลติเธรดนี้ Java ตัวอย่าง เราจะใช้สองเธรดและดึงชื่อของเธรด

ตัวอย่างที่ 1:

GuruThread1.java
package demotest;
public class GuruThread1 implements Runnable{

    /**
     * @param args
     */
    public static void main(String[] args) {
        Thread guruThread1 = new Thread("Guru1");
        Thread guruThread2 = new Thread("Guru2");
        guruThread1.start();
        guruThread2.start();
        System.out.println("Thread names are following:");
        System.out.println(guruThread1.getName());
        System.out.println(guruThread2.getName());
    }
    @Override
    public void run() {
    }
}

คำอธิบายของรหัส:

  • Code 3 แนว: เราได้เรียนวิชาหนึ่งมาแล้วGuruคลาส "Thread1" ซึ่งใช้งานอินเทอร์เฟซ Runnable (ควรใช้งานอินเทอร์เฟซนี้ในทุกคลาสที่มีอินสแตนซ์ที่ตั้งใจจะให้เธรดเรียกใช้งาน)
  • Code 8 แนว: นี่เป็นวิธีการหลักของชั้นเรียน
  • Code 9 แนว: ที่นี่เรากำลังสร้างอินสแตนซ์ของคลาส Thread และสร้างอินสแตนซ์ชื่อ "guruThread1" และสร้างเธรด
  • Code 10 แนว: ที่นี่เรากำลังสร้างอินสแตนซ์คลาส Thread และสร้างอินสแตนซ์ชื่อ "guruThread2" และสร้างเธรด
  • Code 11 แนว: เรากำลังเริ่มเธรดเช่น guruThread1
  • Code 12 แนว: เรากำลังเริ่มเธรดเช่น guruThread2
  • Code 13 แนว: แสดงผลข้อความเป็น “ชื่อเธรดมีดังต่อไปนี้:”
  • Code 14 แนว: รับชื่อของเธรด 1 โดยใช้วิธี getName() ของคลาสเธรด
  • Code 15 แนว: รับชื่อของเธรด 2 โดยใช้วิธี getName() ของคลาสเธรด

เมื่อคุณรันโค้ดข้างต้น คุณจะได้ผลลัพธ์ต่อไปนี้:

Java ตัวอย่างมัลติเธรด

Output:

ชื่อเธรดจะถูกส่งออกที่นี่เป็น

  • Guru1
  • Guru2

2 ตัวอย่าง:

ในมัลติเธรดนี้ใน Java ตัวอย่าง เราจะเรียนรู้เกี่ยวกับวิธีการแทนที่ run() และ start() วิธีการของอินเทอร์เฟซที่รันได้ และสร้างเธรดสองเธรดของคลาสนั้นและรันตามลำดับ

นอกจากนี้ เรายังเรียนอยู่ 2 ชั้นเรียน ได้แก่

  • หนึ่งซึ่งจะใช้อินเทอร์เฟซที่รันได้และ
  • อีกอันหนึ่งซึ่งจะมีวิธีการหลักและดำเนินการตามนั้น
package demotest;
public class GuruThread2 {
 public static void main(String[] args) {
  // TODO Auto-generated method stub
  GuruThread3 threadguru1 = new GuruThread3("guru1");
  threadguru1.start();
  GuruThread3 threadguru2 = new GuruThread3("guru2");
  threadguru2.start();
 }
}
class GuruThread3 implements Runnable {
 Thread guruthread;
 private String guruname;
 GuruThread3(String name) {
  guruname = name;
 }
 @Override
 public void run() {
  System.out.println("Thread running" + guruname);
  for (int i = 0; i < 4; i++) {
   System.out.println(i);
   System.out.println(guruname);
   try {
    Thread.sleep(1000);
   } catch (InterruptedException e) {
    System.out.println("Thread has been interrupted");
   }
  }
 }
 public void start() {
  System.out.println("Thread started");
  if (guruthread == null) {
   guruthread = new Thread(this, guruname);
   guruthread.start();
  }
 }
}

คำอธิบายของรหัส:

  • Code 2 แนว: ที่นี่เรากำลังเรียนอยู่ “GuruThread2” ซึ่งจะมีเมธอดหลักอยู่ภายใน
  • Code 4 แนว: ที่นี่เรากำลังใช้วิธีหลักของชั้นเรียน
  • Code บรรทัดที่ 6-7: ในที่นี้เรากำลังสร้างอินสแตนซ์ของคลาส Guruเธรดที่ 3 (ซึ่งสร้างขึ้นในบรรทัดโค้ดด้านล่าง) มีชื่อว่า “threadguru1” และเรากำลังเริ่มต้นเธรดนี้
  • Code บรรทัดที่ 8-9: ตรงนี้เรากำลังสร้างอินสแตนซ์อีกตัวหนึ่งของคลาส Guruเธรดที่ 3 (ซึ่งสร้างขึ้นในบรรทัดโค้ดด้านล่าง) มีชื่อว่า “threadguru2” และเรากำลังเริ่มต้นเธรดนี้
  • Code 11 แนว: ตรงนี้เรากำลังสร้างคลาส “Guruคลาส "Thread3" ซึ่งใช้งานอินเทอร์เฟซ runnable (ควรใช้งานอินเทอร์เฟซนี้ในทุกคลาสที่มีอินสแตนซ์ที่ตั้งใจจะให้เธรดเรียกใช้งาน)
  • Code บรรทัดที่ 13-14: เรากำลังรับตัวแปรคลาสสองตัวโดยตัวหนึ่งเป็นคลาสเธรดประเภทและอีกตัวเป็นคลาสสตริง
  • Code บรรทัดที่ 15-18: เรากำลังยกเลิก Guruคอนสตรัคเตอร์ Thread3 รับอาร์กิวเมนต์หนึ่งตัวเป็นชนิดสตริง (ซึ่งก็คือชื่อของเธรด) โดยค่าสตริงนี้จะถูกกำหนดให้กับตัวแปรคลาส guruname และชื่อของเธรดก็จะถูกเก็บไว้
  • Code 20 แนว: ที่นี่เรากำลังแทนที่เมธอด run() ของอินเทอร์เฟซที่รันได้
  • Code 21 แนว: เรากำลังส่งออกชื่อเธรดโดยใช้คำสั่ง println
  • Code บรรทัดที่ 22-31: ที่นี่เรากำลังใช้ for loop โดยมีตัวนับเริ่มต้นเป็น 0 และไม่ควรน้อยกว่า 4 (เรารับตัวเลขใดๆ ก็ได้ ดังนั้นที่นี่ลูปจะทำงาน 4 ครั้ง) และเพิ่มตัวนับ เรากำลังพิมพ์ชื่อเธรดและทำให้เธรดเข้าสู่โหมดสลีปเป็นเวลา 1000 มิลลิวินาทีภายในบล็อก try-catch เนื่องจากวิธีสลีปทำให้เกิดข้อยกเว้นในการตรวจสอบ
  • Code 33 แนว: ที่นี่เรากำลังแทนที่วิธีการเริ่มต้นของอินเทอร์เฟซที่รันได้
  • Code 35 แนว: เรากำลังแสดงข้อความ "เริ่มต้นเธรด"
  • Code บรรทัดที่ 36-40: ที่นี่เรากำลังใช้เงื่อนไข if เพื่อตรวจสอบว่า guruthread ตัวแปรคลาสมีค่าอยู่หรือไม่ หากเป็นโมฆะ เรากำลังสร้างอินสแตนซ์โดยใช้คลาสเธรดซึ่งใช้ชื่อเป็นพารามิเตอร์ (ค่าที่ได้รับมอบหมายในตัวสร้าง) หลังจากนั้นเธรดจะเริ่มทำงานโดยใช้เมธอด start()

เมื่อคุณรันโค้ดข้างต้น คุณจะได้ผลลัพธ์ดังต่อไปนี้:

ตัวอย่างมัลติเธรดใน Java

เอาท์พุต:

มีสองเธรด ดังนั้นเราจึงได้รับข้อความสองครั้งว่า "เริ่มต้นเธรด"

เราได้รับชื่อของเธรดตามที่เราส่งออกไป

มันจะเข้าสู่ for loop โดยที่เรากำลังพิมพ์ตัวนับและชื่อเธรดและตัวนับเริ่มต้นด้วย 0

การวนซ้ำดำเนินการสามครั้งและในระหว่างเธรดจะถูกพักเป็นเวลา 1000 มิลลิวินาที

ดังนั้น อันดับแรก เราได้ guru1 จากนั้น guru2 และ guru2 อีกครั้ง เนื่องจากเธรดสลีปที่นี่เป็นเวลา 1000 มิลลิวินาที จากนั้น guru1 ถัดไป และอีกครั้ง guru1 เธรดสลีปเป็นเวลา 1000 มิลลิวินาที ดังนั้นเราจึงได้ guru2 และ guru1

สรุป

ในบทช่วยสอนนี้ เราเห็นแอปพลิเคชันแบบมัลติเธรดใน Java และวิธีการใช้งานเธรดเดี่ยวและมัลติเธรด Java.

  • อธิบายมัลติเธรดใน Java:ในการมัลติเธรด ผู้ใช้จะไม่ถูกบล็อกเนื่องจากเธรดเป็นอิสระและสามารถดำเนินการหลายอย่างพร้อมกันได้
  • ระยะต่างๆ ของวงจรชีวิตของเส้นด้าย ได้แก่
    • ใหม่
    • รันได้
    • เล่น
    • ที่รอ
    • ตาย
  • เรายังได้เรียนรู้เกี่ยวกับ การประสาน ระหว่างเธรดซึ่งช่วยให้แอปพลิเคชันทำงานได้อย่างราบรื่น
  • การเขียนโปรแกรมแบบมัลติเธรดใน Java ทำให้งานแอปพลิเคชันอื่น ๆ ง่ายขึ้น

สรุปโพสต์นี้ด้วย: