โค้ดยิม/จาวาบล็อก/สุ่ม/มัลติเธรด: วิธีการของคลาสเธรดทำอะไร
John Squirrels
ระดับ
San Francisco

มัลติเธรด: วิธีการของคลาสเธรดทำอะไร

เผยแพร่ในกลุ่ม
สวัสดี! วันนี้เราจะพูดถึงมัลติเธรดต่อไป เรามาตรวจสอบคลาสเธรดและเมธอดสองสามอย่างที่ทำกัน เมื่อเราศึกษาวิธีการเรียนก่อนหน้านี้ เรามักจะเขียนสิ่งนี้: <ชื่อวิธีการ> -> <วิธีการทำอะไรบ้าง> มัลติเธรด: เมธอดของคลาสเธรดทำอะไรได้บ้าง - 1สิ่งนี้ใช้ไม่ได้กับThreadเมธอดของ ' :) พวกมันมีตรรกะที่ซับซ้อนกว่าซึ่งคุณไม่สามารถเข้าใจได้หากไม่มีตัวอย่าง

วิธีการ Thread.start()

เริ่มต้นด้วยการทำซ้ำตัวเอง อย่างที่คุณคงจำได้ คุณสามารถสร้างเธรดโดยทำให้คลาสของคุณสืบทอดคลาสThreadและแทนที่run()เมธอด แต่มันจะไม่เริ่มเองแน่นอน ในการทำเช่นนี้ เราเรียกstart()วิธีการ ของวัตถุของเรา มัลติเธรด: วิธีการของคลาสเธรดทำอะไร - 2จำตัวอย่างจากบทเรียนที่แล้ว:
public class MyFirstThread extends Thread {

   @Override
   public void run() {
       System.out.println("Thread executed: " + getName());
   }
}


public class Main {

   public static void main(String[] args) {

       for (int i = 0; i < 10; i++) {
           MyFirstThread thread = new MyFirstThread();
           thread.start();
       }
   }
}
หมายเหตุ:ในการเริ่มเธรด คุณต้องเรียกใช้start()เมธอดพิเศษแทนrun()เมธอด! นี่เป็นข้อผิดพลาดที่เกิดขึ้นได้ง่าย โดยเฉพาะอย่างยิ่งเมื่อคุณเริ่มเรียนมัลติเธรดเป็นครั้งแรก ในตัวอย่างของเรา หากคุณเรียกใช้run()เมธอด 10 ครั้งแทนที่จะเป็นstart()คุณจะได้สิ่งนี้:
public class Main {

   public static void main(String[] args) {

       for (int i = 0; i < 10; i++) {
           MyFirstThread thread = new MyFirstThread();
           thread.run();
       }
   }
}
ดูผลลัพธ์ของโปรแกรมของเรา: เธรดที่ดำเนินการ: เธรด-0 เธรดที่ดำเนินการ: เธรด-1 เธรดที่ดำเนินการ: เธรด-2 เธรดที่ดำเนินการ: เธรด-3 เธรดที่ดำเนินการ: เธรด-4 เธรดที่ดำเนินการ: เธรด-5 เธรดที่ดำเนินการ: เธรด-6 เธรดที่ดำเนินการ: เธรด-7 เธรดที่ดำเนินการ: เธรด-8 เธรดที่ดำเนินการ: เธรด-9 ดูลำดับของเอาต์พุต: ทุกอย่างเกิดขึ้นตามลำดับที่สมบูรณ์แบบ แปลกเหรอ? เราไม่คุ้นเคยกับสิ่งนี้ เพราะเรารู้อยู่แล้วว่าลำดับที่เธรดเริ่มต้นและดำเนินการนั้นถูกกำหนดโดยสติปัญญาที่เหนือกว่าภายในระบบปฏิบัติการของเรา ซึ่งก็คือตัวกำหนดตารางเวลาเธรด บางทีเราอาจจะโชคดี? แน่นอนว่ามันไม่เกี่ยวกับโชค คุณสามารถตรวจสอบได้โดยการเรียกใช้โปรแกรมอีกสองสามครั้ง ประเด็นอยู่ที่การโทรrun()วิธีการโดยตรงไม่มีส่วนเกี่ยวข้องกับมัลติเธรด ในกรณีนี้ โปรแกรมจะดำเนินการบนเธรดหลัก ซึ่งเป็นเธรดเดียวกับที่เรียกใช้main()เมธอด มันพิมพ์ 10 บรรทัดบนคอนโซลอย่างต่อเนื่อง แค่นั้น 10 กระทู้ยังไม่ได้เริ่ม ดังนั้นจำสิ่งนี้ไว้ในอนาคตและตรวจสอบตัวเองอยู่เสมอ หากต้องการrun()ให้เรียกเมธอด ให้start()เรียก ไปต่อกันเถอะ

วิธีการ Thread.sleep()

หากต้องการระงับการดำเนินการของเธรดปัจจุบันชั่วขณะ เราใช้sleep()วิธีการ มัลติเธรด: วิธีการของคลาสเธรดทำอะไร - 3เมธอดsleep()ใช้เวลาเป็นมิลลิวินาทีเป็นอาร์กิวเมนต์ ซึ่งระบุระยะเวลาที่จะทำให้เธรดเข้าสู่โหมดสลีป
public class Main {

   public static void main(String[] args) throws InterruptedException {

       long start = System.currentTimeMillis();

       Thread.sleep(3000);

       System.out.println(" - How long did I sleep? \n - " + ((System.currentTimeMillis()-start)) / 1000 + " seconds");

   }
}
เอาต์พุตคอนโซล: - ฉันหลับไปนานแค่ไหน? - 3 วินาที หมายเหตุ:วิธีsleep()การเป็นแบบคงที่: จะนอนหลับเธรดปัจจุบัน นั่นคือผู้ที่กำลังดำเนินการอยู่ นี่เป็นจุดสำคัญอีกประการหนึ่ง: เธรดการนอนหลับสามารถถูกขัดจังหวะได้ ในกรณีนี้ โปรแกรมจะส่งไฟล์InterruptedException. เราจะพิจารณาตัวอย่างด้านล่าง เกิดอะไรขึ้นหลังจากเธรดตื่นขึ้นมา? มันจะถูกดำเนินการต่อจากที่ค้างไว้หรือไม่? ไม่ หลังจากเธรดกลับมาทำงาน เช่น เวลาผ่านไปเป็นอาร์กิวเมนต์ผ่านไป เธรดThread.sleep()จะเปลี่ยนเป็นรันได้สถานะ. แต่ไม่ได้หมายความว่าตัวกำหนดตารางเวลาของเธรดจะทำงาน มันอาจค่อนข้างที่จะให้ความสำคัญกับเธรดที่ไม่หลับอื่น ๆ และอนุญาตให้เธรดที่เพิ่งตื่นใหม่ของเราทำงานต่อในภายหลัง อย่าลืมสิ่งนี้: การตื่นนอนไม่ได้หมายความว่าต้องทำงานต่อทันที!

วิธีการ Thread.join()

มัลติเธรด: เมธอดของคลาสเธรดทำอะไร - 4เมธอดjoin()จะระงับการดำเนินการของเธรดปัจจุบันจนกว่าเธรดอื่นจะเสร็จสิ้น ถ้าเรามี 2 เธรดt1และt2และ เราเขียน
t1.join()
แล้วt2จะไม่เริ่มจนกว่าt1จะเสร็จงาน วิธีการ นี้join()สามารถใช้เพื่อรับประกันลำดับการดำเนินการของเธรด ลองพิจารณาวิธีjoin()การทำงานในตัวอย่างต่อไปนี้:
public class ThreadExample extends Thread {

   @Override
   public void run() {

       System.out.println("Thread started: " + getName());

       try {
           Thread.sleep(5000);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
       System.out.println("Thread " + getName() + " is finished.");
   }
}


public class Main {

   public static void main(String[] args) throws InterruptedException {

       ThreadExample t1 = new ThreadExample();
       ThreadExample t2 = new ThreadExample();

       t1.start();


 /* The second thread (t2) will start running only after the first thread (t1)
       is finished (or an exception is thrown) */
       try {
           t1.join();
       } catch (InterruptedException e) {
           e.printStackTrace();
       }

       t2.start();

       // The main thread will continue running only after t1 and t2 have finished
       try {
           t1.join();
           t2.join();
       } catch (InterruptedException e) {
           e.printStackTrace();
       }

       System.out.println("All threads have finished. The program is finished.");

   }
}
เราสร้างThreadExampleคลาส ง่ายๆ หน้าที่ของมันคือการแสดงข้อความว่าเธรดได้เริ่มต้นแล้ว เข้าสู่โหมดสลีปเป็นเวลา 5 วินาที จากนั้นจึงรายงานว่างานเสร็จสมบูรณ์ในที่สุด ชิ้นเค้ก ตรรกะหลักอยู่ในMainชั้นเรียน ดูความคิดเห็น: เราใช้join()วิธีการในการจัดการคำสั่งการดำเนินการของเธรดให้สำเร็จ หากคุณจำได้ว่าเราเริ่มต้นหัวข้อนี้อย่างไร คำสั่งดำเนินการจะถูกจัดการโดยตัวกำหนดตารางเวลาของเธรด มันรันเธรดตามที่เห็นสมควร: แต่ละครั้งด้วยวิธีที่แตกต่างกัน ที่นี่เรากำลังใช้วิธีการเพื่อรับประกันว่าt1เธรดจะเริ่มต้นและดำเนินการก่อน จากนั้นจึงt2เธรดและหลังจากนั้นเธรดหลักของโปรแกรมจะดำเนินต่อไป กำลังเดินทางไป. ในโปรแกรมจริง คุณมักจะพบสถานการณ์ที่คุณจำเป็นต้องขัดจังหวะการทำงานของเธรด ตัวอย่างเช่น เธรดของเรากำลังทำงานอยู่ แต่กำลังรอเหตุการณ์หรือเงื่อนไขบางอย่าง หากเกิดขึ้น เธรดจะหยุดทำงาน มันอาจจะสมเหตุสมผลถ้ามีstop()วิธีการ บางอย่าง แต่มันไม่ง่ายอย่างนั้น กาลครั้งหนึ่ง Java มีThread.stop()วิธีการและอนุญาตให้เธรดถูกขัดจังหวะ แต่ภายหลังถูกลบออกจากไลบรารี Java คุณสามารถค้นหาได้ในเอกสาร Oracle และเห็นว่ามีการทำเครื่องหมายว่าเลิกใช้แล้ว. ทำไม เพราะมันหยุดเธรดโดยไม่ได้ทำอะไรอีก ตัวอย่างเช่น เธรดอาจทำงานกับข้อมูลและเปลี่ยนแปลงบางอย่าง จากนั้นในระหว่างการทำงานก็ถูกตัดขาดโดยstop()วิธีการ อย่างกะทันหันและไม่เป็นทางการ หากไม่มีการปิดระบบที่เหมาะสม ไม่มีการเผยแพร่ทรัพยากร ไม่มีแม้แต่การจัดการข้อผิดพลาด — ไม่มีสิ่งนี้ หากต้องการพูดเกินจริงเล็กน้อยstop()วิธีการนี้ก็ทำลายทุกสิ่งที่ขวางหน้า เหมือนกับการดึงสายไฟออกจากเต้ารับเพื่อปิดคอมพิวเตอร์ ใช่ คุณจะได้ผลลัพธ์ที่ต้องการ แต่ทุกคนรู้ดีว่าหลังจากผ่านไปสองสามสัปดาห์ คอมพิวเตอร์จะไม่ขอบคุณคุณที่ทำแบบนั้น นั่นเป็นสาเหตุที่ตรรกะสำหรับการขัดจังหวะเธรดเปลี่ยนไปใน Java และตอนนี้ใช้interrupt()วิธี พิเศษ

วิธีการ Thread.interrupt()

จะเกิดอะไรขึ้นถ้าinterrupt()เมธอดถูกเรียกใช้บนเธรด มี 2 ​​ความเป็นไปได้:
  1. หากอ็อบเจกต์อยู่ในสถานะรอ ตัวอย่างเช่น เนื่องจากjoinหรือsleepเมธอด การรอจะถูกขัดจังหวะและโปรแกรมจะส่งไฟล์InterruptedException.
  2. หากเธรดอยู่ในสถานะทำงาน แฟinterruptedล็กบูลีนจะถูกตั้งค่าบนอ็อบเจ็กต์
แต่เราต้องตรวจสอบค่าของธงนี้บนวัตถุและทำงานให้เสร็จด้วยตัวเอง! นั่นเป็นเหตุผลที่Threadชั้นเรียนมีboolean isInterrupted()วิธีการ กลับไปที่ตัวอย่างนาฬิกาที่อยู่ในบทเรียนในหลักสูตรพื้นฐาน เพื่อความสะดวก เราได้ทำให้ง่ายขึ้นเล็กน้อย:
public class Clock extends Thread {

   public static void main(String[] args) throws InterruptedException {
       Clock clock = new Clock();
       clock.start();

       Thread.sleep(10000);
       clock.interrupt();
   }

   public void run() {
       Thread current = Thread.currentThread();

       while (!current.isInterrupted())
       {
           try {
               Thread.sleep(1000);
           } catch (InterruptedException e) {
               System.out.println("The thread was interrupted");
               break;
           }
           System.out.println("Tick");
       }
   }
}
ในกรณีนี้ นาฬิกาจะเริ่มต้นและเริ่มฟ้องทุกๆ วินาที ในวินาทีที่ 10 เราขัดจังหวะของนาฬิกา ดังที่คุณทราบแล้ว หากเธรดที่เราพยายามขัดจังหวะอยู่ในสถานะรออย่างใดอย่างหนึ่ง ผลลัพธ์InterruptedExceptionคือ นี่เป็นข้อยกเว้นที่ตรวจสอบแล้ว ดังนั้นเราจึงสามารถตรวจจับได้ง่ายและดำเนินการตามตรรกะของเราเพื่อสิ้นสุดโปรแกรม และนั่นเป็นเพียงสิ่งที่เราทำ นี่คือผลลัพธ์ของเรา: ติ๊ก ติ๊ก ติ๊ก ติ๊ก ติ๊ก ติ๊ก ติ๊ก ติ๊ก ติ๊ก เธรดถูกขัดจังหวะ นี่เป็นการสรุปการแนะนำThreadวิธีการที่สำคัญที่สุดของชั้นเรียน ขอให้โชคดี!
ความคิดเห็น
  • เป็นที่นิยม
  • ใหม่
  • เก่า
คุณต้องลงชื่อเข้าใช้เพื่อแสดงความคิดเห็น
หน้านี้ยังไม่มีความคิดเห็นใด ๆ