JavaRush /จาวาบล็อก /Random-TH /มัลติเธรด: วิธีคลาสเธรดทำอะไร

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

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

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

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

   @Override
   public void run() {
       System.out.println("Выполнен поток " + 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()! นี่เป็นข้อผิดพลาดง่าย ๆ โดยเฉพาะอย่างยิ่งเมื่อเรียนรู้มัลติเธรดครั้งแรก หากในตัวอย่างของเรา คุณเรียกใช้เมธอดบนอ็อบเจ็กต์ 10 ครั้งrun()แทนที่จะเป็น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 ดำเนินการเธรด เธรด-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(" - Сколько я проспал? \n - " + ((System.currentTimeMillis()-start)) / 1000 + " секунды");

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

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

Многопоточность: что делают методы класса Thread - 4วิธีการjoin()ระงับการดำเนินการของเธรดปัจจุบันจนกว่าเธรดอื่นจะเสร็จสมบูรณ์ หากเรามี 2 เธรดt1และt2และเราเขียน -
t1.join()
t2จะไม่เริ่มทำงานจนกว่า t1 จะเสร็จสิ้นงาน สามารถใช้ วิธีนี้join()เพื่อให้แน่ใจว่าลำดับการดำเนินการของเธรด ลองดูงานjoin()โดยใช้ตัวอย่าง:
public class ThreadExample extends Thread {

   @Override
   public void run() {

       System.out.println("Начало работы потока " + getName());

       try {
           Thread.sleep(5000);
       } catch (InterruptedException e) {
           e.printStackTrace();
       }
       System.out.println("Поток " + getName() +  " завершил работу.");
   }
}


public class Main {

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

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

       t1.start();


 /*Второй поток t2 начнет выполнение только после того, How будет завершен
       (or бросит исключение) первый поток - t1*/
       try {
           t1.join();
       } catch (InterruptedException e) {
           e.printStackTrace();
       }

       t2.start();

       //Главный поток продолжит работу только после того, How t1 и t2 завершат работу
       try {
           t1.join();
           t2.join();
       } catch (InterruptedException e) {
           e.printStackTrace();
       }

       System.out.println("Все потоки закончor работу, программа завершена");

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

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

จะเกิดอะไรขึ้นถ้าคุณเรียกใช้เมธอด interrupt() บนเธรด ? มี 2 ​​ตัวเลือก:
  1. หากอ็อบเจ็กต์อยู่ในสถานะรอในขณะนั้น หรือjoinการsleepรอจะถูกขัดจังหวะและโปรแกรมจะInterruptedExceptionThrow
  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("Работа потока была прервана");
               break;
           }
           System.out.println("Tik");
       }
   }
}
ในกรณีของเรา นาฬิกาเริ่มเดินและเริ่มเดินทุกวินาที ในวินาทีที่ 10 เราขัดจังหวะการไหลของนาฬิกา ดังที่คุณทราบอยู่แล้วว่า หากเธรดที่เราพยายามขัดจังหวะอยู่ในสถานะรออย่างใดอย่างหนึ่ง ผลลัพธ์ที่ได้คือInterruptedException. ข้อยกเว้นประเภทนี้เป็นข้อยกเว้นที่ได้รับการตรวจสอบ ดังนั้นจึงสามารถตรวจจับได้ง่ายและดำเนินการตรรกะการยกเลิกโปรแกรมของเรา นั่นคือสิ่งที่เราทำ นี่คือผลลัพธ์ของเรา: Tik Tik Tik Tik Tik Tik Tik Tik Tik งานของเธรดถูกขัดจังหวะ นี่เป็นการสรุปการแนะนำวิธีการหลักของชั้นThreadเรียน เพื่อรวบรวมความรู้ของคุณ คุณสามารถชมวิดีโอบรรยายเกี่ยวกับมัลติเธรดนี้:
มันจะทำหน้าที่เป็นวัสดุเพิ่มเติมที่ยอดเยี่ยม! ท้ายที่สุดหลังจากภาพรวมของวิธีการต่างๆ แล้ว ก็บอกได้อย่างชัดเจนว่าเราจะผ่านอะไรต่อไปในหลักสูตรนี้ :) โชคดีนะ!
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION