บทที่ 12
    โปรแกรมแบบเธรด
        (Thread)

    อ.ธนิศ า เครือ ไวศยวรรณ
   คณะเทคโนโลยีส ารสนเทศ
สถาบัน เทคโนโลยีพ ระจอมเกล้า เจ้า
       คุณ ทหารลาดกระบัง
วัต ถุป ระสงค์
 นิย ามความหมายของเธรด

 แนะนำา องค์ป ระกอบของเธรด
 แนะนำา วิธ ีก ารสร้า งคลาสแบบเธรดโดยการ
 สืบ ทอดมาจากคลาสทีช ื่อ Thread หรือ
                          ่                 implements
 อิน เตอร์เ ฟสทีช ื่อ Runnable
                ่
 อธิบ ายขัน ตอนการทำา งานของโปรแกรมแบบเธรด
           ้
 แนะนำา เมธอดต่า งๆทีเ กี่ย วข้อ งกับ การทำา งานของ
                      ่
 คลาส    Thread
 อธิบ ายการใช้ค ีย เ วิร ์ด synchronized
                    ์             เพือ ป้อ งกัน
                                     ่
 การผิด พลาดของการอ่า นข้อ มูล หรือ เขีย นข้อ มูล ที่
 อาจเกิด ขึ้น จากโปรแกรมแบบเธรด
ระบบปฏิบ ัต ิก ารแบบ
             Multitasking
 ระบบปฏิบ ัต ิก ารแบบ   Multitasking คือ ระบบ
 ปฏิบ ัต ิก ารทีอ นุญ าตให้ผ ู้ใ ช้ส ามารถส่ง โปรแกรม
                ่
 ให้ร ะบบปฏิบ ัต ิก ารทำา งานได้ม ากกว่า หนึง  ่
 โปรแกรมพร้อ มกัน ซึ่ง โปรแกรมแต่ล ะโปรแกรมที่
 รัน อยูใ นระบบปฏิบ ัต ิก ารจะสร้า ง process ขึ้น มา
        ่
 ระบบปฏิบ ัต ิก ารแบบ Multitasking จะมี process
 หลายๆ process เข้า คิว รอการทำา งาน โดยระบบ
 ปฏิบ ัต ิก ารจะกำา หนดลำา ดับ ของการทำา งานของ
 process เอง
โปรแกรมมัล ติเ ธรด
 โปรแกรมมัล ติเ ธรดจะเป็น การทำา งานหลายงาน
 พร้อ มกัน โดยแต่ล ะงานจะเรีย กว่า เธรด ซึ่ง จะแตก
 ต่า งจาก process ทีท ำา งานภายใต้ร ะบบปฏิบ ัต ิ
                       ่
 การแบบ Multitasking ตรงที่ process แต่ล ะ
 process จะมีค วามเป็น อิส ระต่อ กัน แต่เ ธรดแต่ล ะ
 เธรดอาจใช้ข ้อ มูล ร่ว มกัน ซึ่ง เปรีย บเสมือ นซีพ ย ู
                                                    ี
 จำา ลอง (Virtual CPU)
 โปรแกรมแบบเธรดจะมีห ลัก การทำา งานทีแ ตกต่า ง
                                      ่
 กัน ทั้ง นี้ข น อยูก ับ ระบบปฏิบ ัต ิก ารและจำา นวนซีพ ย ู
               ึ้   ่                                   ี
โปรแกรมมัล ติเ ธรด
 ในระบบคอมพิว เตอร์ท ม ซ พ ย ูห ลายตัว โปรแกรม
                      ี่ ี ี ี
 แบบเธรดแต่ล ะโปรแกรมสามารถทีจ ะรัน พร้อ มกัน
                             ่
 ได้



 ในระบบคอมพิว เตอร์ท ม ซ พ ย ูต ัว เดีย ว
                      ี่ ี ี ี      ระบบปฏิบ ัต ิ
 การจะเป็น ส่ว นทีจ ะจัด การตารางการทำา งานของ
                  ่
 โปรแกรมเธรด ซึง อาจแบ่ง เวลาการทำา งานของ
                    ่
 ซีพ ย ู
     ี
องค์ป ระกอบของโปรแกรมแบบ
              เธรด
 ซีพ ย ู
      ี     คือ การจัด การทำา งานของโปรแกรมแบบ
  เธรด
 ซอร์ด โค้ด     คือ คลาสในภาษาจาวาทีเ ป็น คลาส
                                     ่
  แบบเธรด
 ออปเจ็ค      คือ ออปเจ็ค ของคลาสแบบเธรด
ออปเจ็ค แบบเธรด
 โปรแกรมภาษาจาวาสามารถกำา หนดให้อ อปเจ็ค
 ของคลาสใดๆ ทำา งานเป็น แบบเธรดได้ ซึ่ง ก็จ ะ
 ทำา ให้ส ามารถรัน โปรแกรมของออปเจ็ค แบบเธรด
 หลายๆออปเจ็ค พร้อ มกัน ได้
 ภาษาจาวาจะมีต ัว จัด ตารางเวลา (Thread
 Scheduler) ของออปเจ็ค แบบ      เธรดเพือ จัด
                                       ่
 ลำา ดับ การทำา งานของออปเจ็ค แบบเธรด
 โปรแกรมบางประเภทจำา เป็น ต้อ งพัฒ นาเป็น แบบ
 เธรดอาทิเ ช่น
  • โปรแกรมภาพกราฟฟิก แบบเคลื่อ นไหว   (Graphics
    Animation)
  • โปรแกรมนาฬิก า
  •
การสร้า งคลาสแบบเธรด
 โปรแกรมแบบเธรดในภาษาจาวาจะใช้ห ลัก การ
 ของการสร้า งออปเจ็ค ของคลาสแบบเธรดแล้ว
 เรีย กใช้เ มธอดเพื่อ ส่ง ให้อ อปเจ็ค ดัง กล่า วทำา งาน
 พร้อ มกัน
 คลาสแบบเธรดในภาษาจาวาคือ คลาสทีส ืบ ทอดมา
                                 ่
 จากคลาสทีช ื่อ Thread หรือ คลาสที่ implements
              ่
 อิน เตอร์เ ฟส Runnable ออปเจ็ค ทีส ร้า งมาจากคลาส
                                  ่
 แบบเธรดจะเรีย กว่า ออปเจ็ค แบบ runnable
ตัว อย่า งโปรแกรม
class PrintName {
 class PrintName {
   String name;
    String name;
   public PrintName(String n) {
    public PrintName(String n) {
         name = n;
          name = n;
   }}
   public void run() {
    public void run() {
        for(int i=0; i<100; i++) {
         for(int i=0; i<100; i++) {
             System.out.println(name);
              System.out.println(name);
         }}
   }}
}}
public class TestPrintName {
 public class TestPrintName {
     public static void main(String args[]) {
      public static void main(String args[]) {
         PrintName p1 = new PrintName("Thana");
          PrintName p1 = new PrintName("Thana");
         PrintName p2 = new PrintName("Somchai");
          PrintName p2 = new PrintName("Somchai");
         p1.run();
          p1.run();
         p2.run();
          p2.run();
     }}
}}
อธิบ ายตัว อย่า งโปรแกรม
 โปรแกรมนี้เ ป็น โปรแกรมทีท ำา งานในรูป แบบปกติ
                           ่
  โดยคลาส PrintName มีเ มธอด run() ซึ่ง จะพิม พ์
  ข้อ ความในคุณ ลัก ษณะ name จำา นวน 100 ครั้ง
 คลาส TestPrintName จะสร้า งออปเจ็ค ของคลาส
  PrintName ขึ้น มาสองออปเจ็ค ทีช อ p1 และ p2 จาก
                                ่ ื่
  นัน จะเรีย กใช้เ มธอด run() เพือ พิม พ์ข ้อ ความออก
    ้                            ่
  มา
 เนือ งจากโปรแกรมนีไ ม่ไ ด้เ ป็น โปรแกรมแบบเธรด
     ่                           ้
  ดัง นั้น ซีพ ีย จ ะทำา คำา สัง p1.run() ให้เ สร็จ ก่อ นแล้ว
                  ู            ่
  จึง จะทำา คำา สั่ง p2.run()
การ     implements      อิน เตอร์เ ฟส        Runnable

 คลาสแบบเธรดสามารถสร้า งได้โ ดยการ
  implements อิน เตอร์เ ฟส Runnable ซึ่ง เมธอดเดีย วที่
  จะต้อ งเขีย นบล็อ กคำา สั่ง คือ เมธอด run() โดยมีร ูป
  แบบดัง นี้
          public class ClassName implements Runnable {
                public void run(){
                      [statements]
                }
          }

 คำา สั่ง ทีอ ยูใ นเมธอด run()
             ่ ่            คือ ชุด คำา สัง ทีต ้อ งการ
                                          ่ ่
  ให้โ ปรแกรมทำา งานในลัก ษณะแบบเธรด
  โปรแกรมจาวาทีร ัน ออปเจ็ค ของคลาสแบบเธรด
                    ่
  ในลัก ษณะนีจ ะต้อ งมีก ารสร้า งออปเจ็ค ของคลาสที่
                 ้
  ชื่อ Thread ก่อ น
การ    implements      อิน เตอร์เ ฟส     Runnable

 Constructor   ของคลาสทีช ื่อ Thread จะมี
                           ่
 argument เพือ รับ ออปเจ็ค ของคลาสที่ implements
                ่
 อิน เตอร์เ ฟส Runnable โดยมีร ูป แบบดัง นี้
          public Thread(Runnable obj)

 ภายหลัง จากทีส ร้า งออปเจ็ค ของคลาสแบบเธรด
               ่
 แล้ว เราสามารถจะสั่ง งานให้อ อปเจ็ค obj เริ่ม
 ทำา งานได้โ ดยการเรีย กใช้เ มธอด start() ทีอ ยูใ น
                                            ่ ่
 คลาสทีช ื่อ Thread
        ่
 คลาสทีช ื่อ Thread
        ่            จะลงทะเบีย นออปเจ็ค ดัง กล่า ว
 ลงในตัว จัด ตารางเวลา และเมือ ซีพ ย เ รีย กรัน
                                ่   ี ู
 โปรแกรมของออปเจ็ค ดัง กล่า ว คำา สั่ง ในเมธอด
 run() จะถูก สั่ง งานตามลำา ดับ
ตัว อย่า งโปรแกรม
class PrintName implements Runnable {
 class PrintName implements Runnable {
     String name;
      String name;
     public PrintName(String n) {
      public PrintName(String n) {
         name = n;
          name = n;
     }}
     public void run() {
      public void run() {
         for(int i=0; i<100; i++) {
          for(int i=0; i<100; i++) {
             System.out.println(name);
              System.out.println(name);
         }}
     }}
}}
public class PrintNameThread {
 public class PrintNameThread {
   public static void main(String args[]) {
    public static void main(String args[]) {
                 PrintName p1 = new PrintName("Thana");
                  PrintName p1 = new PrintName("Thana");
                 PrintName p2 = new PrintName("Somchai");
                  PrintName p2 = new PrintName("Somchai");
                 Thread t1 = new Thread(p1);
                  Thread t1 = new Thread(p1);
                 Thread t2 = new Thread(p2);
                  Thread t2 = new Thread(p2);
                 t1.start();
                  t1.start();
                 t2.start();
                  t2.start();
   }}
}}
อธิบ ายตัว อย่า งโปรแกรม
 ตัว อย่า งโปรแกรมนีเ ป็น การปรับ ปรุง คลาส
                     ้
 PrintName   ให้เ ป็น คลาสแบบ เธรดโดยการ
  implements อิน เตอร์เ ฟส Runnable
 โปรแกรม PrintNameThread สร้า งออปเจ็ค ของคลาส
  PrintName ขึ้น มาสองออปเจ็ค คือ p1 และ p2 ซึ่ง เป็น
  ออปเจ็ค แบบ runnable จากนัน โปรแกรมได้ส ร้า ง
                                    ้
  ออปเจ็ค ของคลาส Thread คือ t1 และ t2 ทีม ซ อร์ด
                                                ่ ี
  โค้ด เดีย วกัน คือ PrintName แต่ม อ อปเจ็ค ต่า งกัน คือ
                                      ี
  p1 และ p2
 เมธอด t1.start()และ t2.start()เป็น การส่ง ออป
 เจ็ค แบบเธรดเข้า ไปจองคิว กับ ตัว จัด ตารางเวลา
การ    extends     คลาสที่ช อ
                                ื่        Thread

 คลาสแบบเธรดสามารถสร้า งได้โ ดยการสืบ ทอด
 คลาสทีช ื่อ Thread ซึง จะต้อ งมีก าร override
       ่              ่
 เมธอด run() โดยมีร ูป แบบดัง นี้
    public class ClassName extends Thread {
        public void run(){
              [statements]
        }
    }

 เราสามารถเรีย กใช้เ มธอด start()เพื่อ ลงทะเบีย น
 ออปเจ็ค ของคลาสดัง กล่า วในตัว จัด ตารางเวลาได้
 โดยไม่จ ำา เป็น ต้อ งสร้า งออปเจ็ค ของคลาส Thread
 และเมือ ซีพ ย เ รีย กรัน โปรแกรมของออปเจ็ค คำา สั่ง
        ่    ี ู
 ในเมธอดแบบ overriden ที่ช อ run() จะถูก สัง งาน
                                 ื่            ่
 ต่อ ไป
ตัว อย่า งโปรแกรม
class PrintName extends Thread {{
 class PrintName extends Thread
    String name;
     String name;
       public PrintName(String n) {{
        public PrintName(String n)
     name == n;
      name    n;
      }}
      public void run() {{
       public void run()
            for(int i=0; i<100; i++) {{
             for(int i=0; i<100; i++)
            System.out.println(name);
             System.out.println(name);
     }}
       }}
}}
public class PrintNameThread {{
 public class PrintNameThread
     public static void main(String args[]) {{
      public static void main(String args[])
     PrintName p1 == new PrintName();
      PrintName p1    new PrintName();
     PrintName p2 == new PrintName();
      PrintName p2    new PrintName();
     p1.run();
      p1.run();
     p2.run();
      p2.run();
     }}
}}
เปรีย บเทีย บวิธ ีก ารสร้า งคลาสแบบ
                เธรด
 การสร้า งคลาสโดยการสืบ ทอดคลาสทีช ื่อ Thread
                                  ่
 จะเป็น การเขีย นโปรแกรมทีส ั้น กว่า
                          ่
 การสร้า งคลาสโดย implements อิน เตอร์เ ฟส
  Runnable จะมีห ลัก การเชิง ออปเจ็ค ทีด ก ว่า
                                       ่ ี
 เนือ งจากคลาสดัง กล่า วไม่ใ ช่ค ลาสทีส ืบ ทอดมา
    ่                                 ่
 จากคลาส Thread โดยตรง นอกจากนีย ง ทำา ให้ก าร
                                        ้ ั
 เขีย นโปรแกรมมีร ูป แบบเดีย วกัน เสมอ เพราะ
 คลาสในจาวาจะสืบ ทอดได้เ พีย งคลาสเดีย ว
รูป แสดงวงจรการทำา งานของเธรด
สถานะ New
 เป็น สถานะเมือ มีก ารสร้า งออปเจ็ค ของคลาสแบบ
               ่
 เธรด ก่อ นทีจ ะมีก ารเรีย กใช้เ มธอดทีช ื่อ
             ่                         ่       start()
สถานะ Runnable และสถานะ
           Running
 Runnable    เป็น สถานะที่อ อปเจ็ค แบบเธรดพร้อ มที่
  จะทำา งาน ซึ่ง อาจเกิด จากการเรีย กใช้เ มธอด
  start() หรือ เกิด จากการกลับ มาจากสถานะที่
  เป็น การบล็อ กเธรด
 ออปเจ็ค แบบเธรดทีอ ยูใ นสถานะ Runnable จะ
                       ่ ่
  เข้า สูส ถานะ Running ซึ่ง เป็น สถานะทีซ พ ีย ร ัน คำา
         ่                                ่ ี ู
  สั่ง ของออปเจ็ค แบบเธรด เมือ ตัว จัด ตารางเวลาจัด
                               ่
  เวลาทำา งานให้โ ดยจะทำา งานตามชุด คำา สัง ใน
                                             ่
  เมธอด run()
 ออปเจ็ค แบบเธรดจะหยุด การทำา งานและกลับ เข้า สู่
 สถานะ Runnable อีก ครั้ง เมือ ตัว จัด ตารางเวลา
                               ่
 เปลี่ย นให้อ อปเจ็ค แบบเธรดอื่น ๆ ทีอ ยูใ นสถานะ
                                     ่ ่
สถานะ Blocked
 ออปเจ็ค แบบเธรดทีอ ยูใ นสถานะ
                   ่ ่             Running อาจ
 ถูก บล็อ กแล้ว ย้า ยไปอยูใ นสถานะ Blocked ได้
                          ่
 เนือ งจากเหตุก ารณ์ต ่า งๆดัง นี้
    ่
  • มีก ารเรีย กใช้เ มธอด sleep()
  • ออปเจ็ค แบบเธรดรอรับ การทำา งานที่เ ป็น อิน พุต หรือ
    เอาท์พ ุต
  • มีก ารเรีย กใช้เ มธอดที่ช ื่อ wait()
  • ออปเจ็ค แบบเธรดถูก เรีย กโดยเมธอด          suspend()
 ออปเจ็ค แบบเธรดทีอ ยูใ นสถานะ
                   ่ ่              Blocked จะกลับ
 เข้า สูส ถานะ Runnable ได้อ ีก ครั้ง หนึง จาก
        ่                                ่
 เหตุก ารณ์ต ่า งๆดัง นี้
  • เมื่อ หมดระยะเวลาการพัก ที่ก ำา หนดในเมธอด sleep()
    หรือ ถูก อิน เตอร์ร ับ
  • เมื่อ มีก ารส่ง ข้อ มูล อิน พุต หรือ เอาท์พ ุต
  • เมื่อ มีอ อปเจ็ค แบบเธรดตัว อื่น เรีย กเมธอด     notify()   หรือ
สถานะ Dead
 ออปเจ็ค แบบเธรดจะเข้า สู่ส ถานะ   Dead เมือ สิน สุด
                                             ่ ้
 การทำา งานเนือ งจากสิ้น สุด การทำา งานในชุด คำา สัง
              ่                                    ่
 ของเมธอด run() หรือ เมือ มีก ารส่ง ออปเจ็ค ประเภท
                              ่
 Exception      ทีไ ม่ไ ด้ม ก ารตรวจจับ (catch) ใน
                  ่         ี
 เมธอด run()
เมธอดของคลาส                     Thread

 คลาสทีช ื่อ Thread
        ่                   มีเ มธอดต่า งๆทีส ำา คัญ ดัง นี้
                                            ่
   •   void run()
       เป็น เมธอดที่จ ะถูก เรีย กใช้เ มื่อ ซีพ ีย ูร ัน โปรแกรมออป
       เจ็ค แบบเธรด
   •   void start()
       เป็น เมธอดที่เ รีย กใช้ง านเพื่อ กำา หนดให้อ อปเจ็ค แบบ
       เธรด เริ่ม ทำา งานโดยเข้า สู่ส ถานะ Runnable
   •   void suspend()
       เป็น เมธอดที่ใ ช้ใ นการหยุด การทำา งานของออปเจ็ค แบบ
       เธรด เมธอดนี้ไ ม่ม ีก ารแนะนำา ให้ใ ช้ใ นภาษาจาวา
       ตั้ง แต่เ วอร์ช ั่น 1.2 เพื่อ ป้อ งกัน ไม่ใ ห้เ กิด เหตุก ารณ์
       deadlock ที่จ ะกล่า วถึง ต่อ ไป
   •   void resume()
       เป็น เมธอดที่ใ ช้ใ นการสั่ง ให้อ อปเจ็ค แบบเธรดกลับ เข้า
เมธอดของคลาส                    Thread

 คลาสทีช ื่อ Thread
        ่                  มีเ มธอดต่า งๆทีส ำา คัญ ดัง นี้
                                           ่
   •   static void sleep(long mills)
       เป็น เมธอดที่ก ำา หนดให้อ อปเจ็ค แบบเธรดที่อ ยู่ใ นสถานะ
       Running หยุด การทำา งานเป็น เวลา mills มิล ลิว ิน าที
       หรือ จนกว่า ถูก อิน เตอร์ร ับ
   •   boolean isAlive()
       เป็น เมธอดที่ใ ช้ต รวจสอบว่า ออปเจ็ค แบบเธรดยัง มี
       สถานะ Running อยู่ห รือ ไม่
   •   void setPriority(int p)
       เป็น เมธอดที่ใ ช้ใ นการกำา หนดลำา ดับ ความสำา คัญ ขอ
       งออปเจ็ค แบบเธรด ซึ่ง จะมีค ่า ได้ร ะหว่า ง 1 ถึง 10
       โดยที่ค ่า 10 เป็น ค่า สูง สุด
   •   int getPriority()
       เป็น เมธอดที่ใ ช้ใ นการเรีย กดูค ่า ลำา ดับ ความสำา คัญ ขอ
Synchronization
 กรณีท อ อปเจ็ค แบบเธรดใช้ข ้อ มูล ร่ว มกัน อาจเกิด
        ี่
 ปัญ หาทีเ รีย กว่า race condition ขึ้น ได้
         ่
 กรณีท อ อปเจ็ค แบบเธรดต่า งแย่ง กัน จัด การข้อ มูล
        ี่
 ทำา ให้ไ ด้ข ้อ มูล ทีผ ิด พลาด
                       ่
ตัว อย่า งโปรแกรม
public class BankSystemUnSync{
 public class BankSystemUnSync{
   public static void main(String[] args){
    public static void main(String[] args){

          final int NACCOUNTS = 10;
           final int NACCOUNTS = 10;
          final int INITIAL_BALANCE = 10000;
           final int INITIAL_BALANCE = 10000;

           Bank b = new Bank(NACCOUNTS, INITIAL_BALANCE);
            Bank b = new Bank(NACCOUNTS, INITIAL_BALANCE);
           int i;
            int i;
           for (i = 0; i < NACCOUNTS; i++) {
            for (i = 0; i < NACCOUNTS; i++) {
                   Transfer t = new Transfer(b, i,INITIAL_BALANCE);
                    Transfer t = new Transfer(b, i,INITIAL_BALANCE);
                   t.setPriority(Thread.NORM_PRIORITY + i % 2);
                    t.setPriority(Thread.NORM_PRIORITY + i % 2);
                   t.start();
                    t.start();
          }}
     }}
}}
ตัว อย่า งโปรแกรม
class Bank{
 class Bank{
   public static final int NTEST = 10000;
    public static final int NTEST = 10000;
   private final int[] accounts;
    private final int[] accounts;
   private long ntransacts = 0;
    private long ntransacts = 0;

   public Bank(int n, int initialBalance) {
    public Bank(int n, int initialBalance) {
               accounts = new int[n];
                accounts = new int[n];
      for (int i = 0; i < accounts.length; i++) {
       for (int i = 0; i < accounts.length; i++) {
         accounts[i] = initialBalance;
          accounts[i] = initialBalance;
      }}
      ntransacts = 0;
       ntransacts = 0;
   }}

   public void transfer(int from, int to, int amount) {
    public void transfer(int from, int to, int amount) {
        if (accounts[from] < amount) {
         if (accounts[from] < amount) {
                return;
                 return;
       }}
ตัว อย่า งโปรแกรม
        accounts[from] -= amount;
         accounts[from] -= amount;
        accounts[to] += amount;
         accounts[to] += amount;
        ntransacts++;
         ntransacts++;
        if (ntransacts % NTEST == 0) {
         if (ntransacts % NTEST == 0) {
                 test();
                  test();
        }}
     }}
     public void test(){
      public void test(){
          int sum = 0;
           int sum = 0;
         for (int i = 0; i < accounts.length; i++){
          for (int i = 0; i < accounts.length; i++){
             sum += accounts[i];
              sum += accounts[i];
         }}
         System.out.println("Transactions:" + ntransacts
          System.out.println("Transactions:" + ntransacts
                                               + " Sum: " + sum);
                                                + " Sum: " + sum);
     }}
     public int size(){
      public int size(){
          return accounts.length;
           return accounts.length;
     }}
}}
ตัว อย่า งโปรแกรม
class Transfer extends Thread{
 class Transfer extends Thread{
   private Bank bank;
    private Bank bank;
   private int fromAccount;
    private int fromAccount;
   private int maxAmount;
    private int maxAmount;
   public Transfer(Bank b, int from, int max) {
    public Transfer(Bank b, int from, int max) {
        bank = b;
         bank = b;
        fromAccount = from;
         fromAccount = from;
        maxAmount = max;
         maxAmount = max;
   }}
   public void run() {
    public void run() {
        try {
         try {
          while (!interrupted()) {
            while (!interrupted()) {
             int toAccount = (int)(bank.size() * Math.random());
              int toAccount = (int)(bank.size() * Math.random());
              int amount = (int)(maxAmount * Math.random());
               int amount = (int)(maxAmount * Math.random());
              bank.transfer(fromAccount, toAccount, amount);
               bank.transfer(fromAccount, toAccount, amount);
              Thread.sleep((int) (Math.random() * 10));
               Thread.sleep((int) (Math.random() * 10));
          }}
       }}
       catch(InterruptedException e) {}
        catch(InterruptedException e) {}
   }}
}}
ตัว อย่า งโปรแกรม
class TransferThread extends Thread {{
 class TransferThread extends Thread
    private Bank bank;
     private Bank bank;
    private int sourceAcct;
     private int sourceAcct;
    private int destAcct;
     private int destAcct;
    public TransferThread(Bank b,int s,int d) {{
     public TransferThread(Bank b,int s,int d)
         bank == b;
          bank    b;
         sourceAcct == s;
          sourceAcct    s;
         destAcct == d;
          destAcct    d;
    }}
    public void run() {{
     public void run()
         try {{
          try
              while (!interrupted()) {{
               while (!interrupted())
                   bank.transfer(sourceAcct,destAcct);
                    bank.transfer(sourceAcct,destAcct);
                   sleep(1);
                    sleep(1);
              }}
         }} catch (Exception e) {{ }}
             catch (Exception e)
    }}
}}
อธิบ ายตัว อย่า งโปรแกรม
 เป็น ตัว อย่า งกรณีข องโปรแกรมจำา ลองระบบ
 ธนาคารซึ่ง จะมีค ลาส Bank ทีม บัญ ชีล ูก ค้า อยู่ 10
                               ่ ี
 บัญ ชีโ ดยมีย อดเงิน รวมของทุก บัญ ชีท ง สิ้น จำา นวน
                                          ั้
 100,000 บาท และมีเ มธอด transfer() ที่ใ ช้ใ นการ
 โอนเงิน ระหว่า งบัญ ชีห นึง ไปยัง อีก บัญ ชีห นึง โดย
                           ่                     ่
 ใช้ค ำา สัง
           ่
  •   accounts[from] -= amount
  •   accounts[to] += amount
      ตัว แปร from คือ หมายเลขบัญ ชีท ี่ต ้อ งการตัด โอนเงิน ไป
      ตัว แปร to คือ หมายเลขบัญ ชีท ี่ต ้อ งการรับ เงิน เข้า มา
 คลาส TransferThread เป็น คลาสแบบเธรดทีม ี ่
  เมธอด run() ซึ่ง เรีย กใช้อ อปเจ็ค ของคลาส Bank
 เพือ โอนเงิน ระหว่า งบัญ ชีใ ดๆแบบสุ่ม โดยจะ
    ่
อธิบ ายผลลัพ ธ์ท ี่ไ ด้จ ากการรัน
            โปรแกรม
 ตัว อย่า งผลลัพ ธ์ท ไ ด้จ ากการรัน โปรแกรมนี้
                      ี่                                   จะ
 เห็น ได้ว ่า เมือ รัน โปรแกรมไปได้ร ะยะหนึง จะมีผ ล
                 ่                                   ่
 รวมยอดเงิน ทีผ ิด พลาด ทั้ง นี้เ นื่อ งจากเกิด ปัญ หาที่
                   ่
 เรีย กว่า race condition ซึง ออปเจ็ค แบบเธรด
                                     ่
 แต่ล ะตัว อาจหยุด ทำา งานระหว่า งขั้น ตอนใดๆของ
 คำา สั่ง ในเมธอด run() เพือ ให้อ อปเจ็ค แบบเธรดตัว
                                 ่
 อื่น ได้ท ำา งาน ซึ่ง คำา สั่ง แต่ล ะคำา สั่ง อาจมีข ั้น ตอน
 การทำา งานหลายขั้น เช่น คำา สัง       ่
            account[to] += amount

 จะไม่ใ ช่เ ป็น เพีย งคำา สั่ง เดีย วแต่จ ะมีข ั้น ตอนต่า งๆ
 ดัง นี้
   • โหลด account[to] เข้า สู่ร ีจ ีส เตอร์ใ นซีพ ีย ู
   • บวกค่า ในรีจ ีสเตอร์ด ้ว ยค่า ของ amount
คีย ์เ วิร ์ด   synchronized

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

 การใช้ค ีย เ วิร ์ด synchronized
             ์                          เพือ ล็อ กคำา สั่ง ทำา ได้
                                           ่
  สองรูป แบบคือ
   • กำา หนดคีย ์เ วิร ์ด synchronized ที่เ มธอด
   • กำา หนดบล็อ กคีย ์เ วิร ์ด synchronized

 ตัว อย่า งของการกำา หนดเมธอดทีช ื่อ transfer()
                                ่                             ให้
  เป็น แบบ   synchronized   สามารถทำา ได้ด ัง นี้
    public synchronized void transfer(int from, int to,
                                                    int amount) {
                  ...
    }
เมธอด      wait()    และ     notify()

 เมธอด wait()  และ notify() หรือ notifyAll() เป็น
 เมธอดทีใ ช้ก บ เมธอดหรือ บล็อ กคำา สั่ง ทีเ ป็น
        ่     ั                             ่
 synchronized
 เมธอด wait() จะมีผ ลให้อ อปเจ็ค แบบเธรดทีอ ยูใ น
                                                ่ ่
 สถานะ Running กลับ เข้า สูส ถานะบล็อ กเพื่อ รอ
                              ่
 ให้อ อปเจ็ค แบบเธรดตัว อื่น ๆแจ้ง ให้ก ลับ เข้า สู่
 สถานะ Runnable โดยใช้เ มธอด notify() หรือ
 notifyAll()
ตัว อย่า งการใช้ค ีย ์เ วิร ์ด                  synchronized
public class BankSystem {
 public class BankSystem {
   public static void main(String[] args) {
    public static void main(String[] args) {

          final int NACCOUNTS = 10;
           final int NACCOUNTS = 10;
          final int INITIAL_BALANCE = 10000;
           final int INITIAL_BALANCE = 10000;

           Bank b = new Bank(NACCOUNTS, INITIAL_BALANCE);
            Bank b = new Bank(NACCOUNTS, INITIAL_BALANCE);
           int i;
            int i;
           for (i = 0; i < NACCOUNTS; i++) {
            for (i = 0; i < NACCOUNTS; i++) {
               Transfer t = new Transfer(b, i, INITIAL_BALANCE);
                Transfer t = new Transfer(b, i, INITIAL_BALANCE);
                t.setPriority(Thread.NORM_PRIORITY + i % 2);
                 t.setPriority(Thread.NORM_PRIORITY + i % 2);
                t.start();
                 t.start();
          }}
     }}
}}
ตัว อย่า งการใช้ค ีย ์เ วิร ์ด                 synchronized
  class Bank {
   class Bank {
     public static final int NTEST = 10000;
      public static final int NTEST = 10000;
     private final int[] accounts;
      private final int[] accounts;
     private long ntransacts = 0;
      private long ntransacts = 0;

     public Bank(int n, int initialBalance) {
      public Bank(int n, int initialBalance) {
                  accounts = new int[n];
                   accounts = new int[n];
        for (int i = 0; i < accounts.length; i++) {
         for (int i = 0; i < accounts.length; i++) {
            accounts[i] = initialBalance;
             accounts[i] = initialBalance;
        }}
        ntransacts = 0;
         ntransacts = 0;
     }}
     public synchronized void transfer(int from, int to, int
      public synchronized void transfer(int from, int to, int
                                                     amount) {
                                                      amount) {
          try{
           try{
                  while (accounts[from] < amount){
                   while (accounts[from] < amount){
               wait();
                wait();
            }}
ตัว อย่า งการใช้ค ีย ์เ วิร ์ด                synchronized
           accounts[from] -= amount;
            accounts[from] -= amount;
            accounts[to] += amount;
             accounts[to] += amount;
            ntransacts++;
             ntransacts++;
            notifyAll();
             notifyAll();
            if (ntransacts % NTEST == 0) {
             if (ntransacts % NTEST == 0) {
                  test();
                   test();
            }}
        } catch(InterruptedException e) {}
         } catch(InterruptedException e) {}
   }}
   public synchronized void test() {
    public synchronized void test() {
        int sum = 0;
         int sum = 0;

         for (int i = 0; i < accounts.length; i++){
          for (int i = 0; i < accounts.length; i++){
                 sum += accounts[i];
                  sum += accounts[i];
         }}
          System.out.println("Transactions:" + ntransacts
           System.out.println("Transactions:" + ntransacts
                                               + " Sum: " + sum);
                                                + " Sum: " + sum);
   }}
ตัว อย่า งการใช้ค ีย ์เ วิร ์ด                synchronized
      public int size(){
       public int size(){
           return accounts.length;
            return accounts.length;
      }}
 }}

 class Transfer extends Thread{
  class Transfer extends Thread{
    private Bank bank;
     private Bank bank;
    private int fromAccount;
     private int fromAccount;
    private int maxAmount;
     private int maxAmount;

      public Transfer(Bank b, int from, int max){
       public Transfer(Bank b, int from, int max){
           bank = b;
            bank = b;
           fromAccount = from;
            fromAccount = from;
           maxAmount = max;
            maxAmount = max;
      }}
ตัว อย่า งการใช้ค ีย ์เ วิร ์ด                  synchronized
     public void run() {
      public void run() {
        try {
         try {
             while (!interrupted()) {
              while (!interrupted()) {
                  int toAccount = (int)(bank.size() * Math.random());
                   int toAccount = (int)(bank.size() * Math.random());
                  int amount = (int)(maxAmount * Math.random());
                   int amount = (int)(maxAmount * Math.random());
                  bank.transfer(fromAccount, toAccount, amount);
                   bank.transfer(fromAccount, toAccount, amount);
                  Thread.sleep(1);
                   Thread.sleep(1);
            }}
        }}
        catch(InterruptedException e) {}
         catch(InterruptedException e) {}
     }}
}}
Deadlock
 ในกรณีท อ อปเจ็ค แบบเธรดทุก ออปเจ็ค ถูก เรีย กใช้
          ี่
  คำา สั่ง wait() ทัง หมดโดยไม่ม อ อปเจ็ค ใดสามารถ
                      ้             ี
  เรีย กคำา สั่ง notify() หรือ notifyAll()ได้ จะเป็น
  กรณีท อ อปเจ็ค แต่ล ะตัว รอการปลดล็อ กจากกัน
           ี่
  และกัน จึง ทำา ให้เ กิด สถานการณ์ท เ รีย กว่าี่
  deadlock ซึ่ง จะทำา ให้ไ ม่ม ก ารทำา งานใดๆเกิด ขึ้น
                                  ี
 ตัว อย่า งเช่น ถ้า คลาส Bank ของโปรแกรมทีผ ่า นมา ่
  มีบ ัญ ชีเ พีย งสองบัญ ชีโ ดยบัญ ชีท ห นึ่ง มีย อดเงิน
                                          ี่
  2,000 บาท และบัญ ชีท ส องมีย อดเงิน 3,000 บาท
                             ี่
  และถ้า ออปเจ็ค แบบเธรดตัว ทีห นึง มีค ำา สั่ง
                                      ่ ่
  transfer()เพือ โอนเงิน จากบัญ ชีท ห นึง ไปยัง บัญ ชีท ี่
                    ่                        ี่ ่
  สองเป็น เงิน 3,000 บาท และออปเจ็ค แบบเธรดตัว
  ทีส องมีค ำา สัง transfer()เพือ โอนเงิน จากบัญ ชีท ี่
    ่             ่             ่
  สองไปยัง บัญ ชีท ห นึง เป็น เงิน 4,000 บาท กรณีน ี้
                        ี่ ่
รูป แสดงเหตุก ารณ์ Deadlock
สรุป เนื้อ หาของบท
 เธรดจะแตกต่า งจาก       process ทีท ำา งานภายใต้
                                    ่
 ระบบปฏิบ ัต ิก ารแบบ Multitasking ตรงที่
 process แต่ล ะ process จะมีค วามเป็น อิส ระต่อ
 กัน แต่เ ธรดแต่ล ะเธรดอาจใช้ข ้อ มูล ร่ว มกัน ซึ่ง
 เปรีย บเสมือ นซีพ ย จ ำา ลอง (Virtual CPU)
                   ี ู
 เธรดประกอบไปด้ว ยซีพ ย ู
                       ี     ซอร์ด โค้ด และออปเจ็ค
 คลาสแบบเธรดในภาษาจาวาคือ คลาสทีส ืบ ทอดมา
                                 ่
 จากคลาสทีช ื่อ Thread หรือ คลาสที่
              ่                       implements
 อิน เตอร์เ ฟส Runnable
 ภายในคลาสแบบเธรดจะต้อ งมีเ มธอด run()        ทีไ ม่ม ี
                                                 ่
 การรับ argument ใดๆเข้า มา
สรุป เนื้อ หาของบท
 สถานะของเธรดอาจจะเป็น         New, Runnable,
  Running, Blocked หรือ Dead การเข้า สู่ส ถานะ
  Running จะขึ้น อยูก บ ตัว จัด ตารางเวลา
                    ่ ั
 เราสามารถทีจ ะใช้ค ีย ์เ วิร ์ด ทีช ื่อ synchronized
             ่                      ่             เพือ่
  ล็อ ก (lock) ชุด คำา สัง ที่
                         ่       ออปเจ็ค แบบเธรดต้อ ง
  กระทำา พร้อ มกัน ไว้ไ ด้
 Deadlock  หมายถึง การทีอ อปเจ็ค แต่ล ะตัว รอการ
                         ่
  ปลดล็อ กจากกัน และกัน ทำา ให้ไ ม่ม ก ารทำา งานใดๆ
                                     ี
  เกิด ขี้น
แบบฝึก หัด
 ข้อ ที่   1
    • ทดลองเขีย นโปรแกรมนาฬิก าแบบดิจ ิต อล   โดยให้ม ี
     การทำา งานแบบ Thread

More Related Content

PDF
Java Programming: การสร้างส่วนต่อประสานกราฟิกกับผู้ใช้ (Java GUI)
PDF
Java Programming: โครงสร้างควบคุม
PDF
Java Programming: อะเรย์และคอลเล็กชั่น
PPT
Java Programming [9/12]: Exception Handling
PDF
Java Programming: คลาสอินพุตและเอาต์พุต
PDF
Java Programming: การเขียนโปรแกรมภาษาจาวาเชิงอ็อบเจกต์
PPT
Java Programming [4/12] : Object Oriented Concept
PDF
Java Programming: การจัดการกับข้อผิดพลาด
Java Programming: การสร้างส่วนต่อประสานกราฟิกกับผู้ใช้ (Java GUI)
Java Programming: โครงสร้างควบคุม
Java Programming: อะเรย์และคอลเล็กชั่น
Java Programming [9/12]: Exception Handling
Java Programming: คลาสอินพุตและเอาต์พุต
Java Programming: การเขียนโปรแกรมภาษาจาวาเชิงอ็อบเจกต์
Java Programming [4/12] : Object Oriented Concept
Java Programming: การจัดการกับข้อผิดพลาด

What's hot (19)

PDF
ความรู้เบื้องต้นภาษาจาวา
PDF
Java Programming: หลักการเชิงอ็อบเจกต์
PDF
PPT
Error handle-OOP(รูปแบบและลักษณะการ Error ในโปรแกรม)
PPT
Java Programming [8/12] : Arrays and Collection
PDF
พื้นฐานภาษาจาวา
PDF
พื้นฐานภาษาจาวา
PPT
พื้นฐานภาษาจาวา
PDF
คลาสและการเขียนโปรแกรมเชิงวัตถุเบื้องต้น
PPTX
Reference :: Java :: เต็ม
PPTX
ภาษาจาวา 1
PPTX
Lab Computer Programming 1
PDF
การเขียนฟังก์ชั่นในภาษา C
PDF
คลาสและการเขียนโปรแกรมเชิงวัตถุเบื้องต้น
PDF
บทที่ 5 คลาส
PPT
Java Programming [10/12]: Java Applet
PDF
Java-Chapter 01 Introduction to Java Programming
PPTX
บทที่2
ความรู้เบื้องต้นภาษาจาวา
Java Programming: หลักการเชิงอ็อบเจกต์
Error handle-OOP(รูปแบบและลักษณะการ Error ในโปรแกรม)
Java Programming [8/12] : Arrays and Collection
พื้นฐานภาษาจาวา
พื้นฐานภาษาจาวา
พื้นฐานภาษาจาวา
คลาสและการเขียนโปรแกรมเชิงวัตถุเบื้องต้น
Reference :: Java :: เต็ม
ภาษาจาวา 1
Lab Computer Programming 1
การเขียนฟังก์ชั่นในภาษา C
คลาสและการเขียนโปรแกรมเชิงวัตถุเบื้องต้น
บทที่ 5 คลาส
Java Programming [10/12]: Java Applet
Java-Chapter 01 Introduction to Java Programming
บทที่2
Ad

Similar to Java Programming [12/12] : Thread (20)

PPT
PPT
บทที่ 6 คลาสและการเขียนโปรแกรม
PPT
Chapter1 uml3
PPT
Chapter1 uml3
PPTX
Computer Programming 1
PPTX
Computer Programming 4
PDF
Java-Chapter 12 Classes and Objects
PDF
(Big One) C Language - 07 object linkedlist
PPT
Java Programming [2/12] : Overview of Java Programming Language
PDF
Java-Chapter 08 Methods
PDF
Java 7&12 6 2
PPTX
คลาสและการเขียนโปรแกรมเชิงวัตถุเบื้องต้น
DOC
ผังงาน (Flowchart)
PDF
ฟังก์ชั่นย่อยและโปรแกรมมาตรฐาน ม.6.1
PDF
หลักการเขียนโปรแกรม
PDF
ภาษา C#
DOC
PDF
6.Flow control
PDF
ประวัติความเป็นมาภาษาซี
บทที่ 6 คลาสและการเขียนโปรแกรม
Chapter1 uml3
Chapter1 uml3
Computer Programming 1
Computer Programming 4
Java-Chapter 12 Classes and Objects
(Big One) C Language - 07 object linkedlist
Java Programming [2/12] : Overview of Java Programming Language
Java-Chapter 08 Methods
Java 7&12 6 2
คลาสและการเขียนโปรแกรมเชิงวัตถุเบื้องต้น
ผังงาน (Flowchart)
ฟังก์ชั่นย่อยและโปรแกรมมาตรฐาน ม.6.1
หลักการเขียนโปรแกรม
ภาษา C#
6.Flow control
ประวัติความเป็นมาภาษาซี
Ad

More from IMC Institute (20)

PDF
นิตยสาร Digital Trends ฉบับที่ 14
PDF
Digital trends Vol 4 No. 13 Sep-Dec 2019
PDF
บทความ The evolution of AI
PDF
IT Trends eMagazine Vol 4. No.12
PDF
เพราะเหตุใด Digitization ไม่ตอบโจทย์ Digital Transformation
PDF
IT Trends 2019: Putting Digital Transformation to Work
PDF
มูลค่าตลาดดิจิทัลไทย 3 อุตสาหกรรม
PDF
IT Trends eMagazine Vol 4. No.11
PDF
แนวทางการทำ Digital transformation
PDF
บทความ The New Silicon Valley
PDF
นิตยสาร IT Trends ของ IMC Institute ฉบับที่ 10
PDF
แนวทางการทำ Digital transformation
PDF
The Power of Big Data for a new economy (Sample)
PDF
บทความ Robotics แนวโน้มใหม่สู่บริการเฉพาะทาง
PDF
IT Trends eMagazine Vol 3. No.9
PDF
Thailand software & software market survey 2016
PPTX
Developing Business Blockchain Applications on Hyperledger
PDF
Digital transformation @thanachart.org
PDF
บทความ Big Data จากบล็อก thanachart.org
PDF
กลยุทธ์ 5 ด้านกับการทำ Digital Transformation
นิตยสาร Digital Trends ฉบับที่ 14
Digital trends Vol 4 No. 13 Sep-Dec 2019
บทความ The evolution of AI
IT Trends eMagazine Vol 4. No.12
เพราะเหตุใด Digitization ไม่ตอบโจทย์ Digital Transformation
IT Trends 2019: Putting Digital Transformation to Work
มูลค่าตลาดดิจิทัลไทย 3 อุตสาหกรรม
IT Trends eMagazine Vol 4. No.11
แนวทางการทำ Digital transformation
บทความ The New Silicon Valley
นิตยสาร IT Trends ของ IMC Institute ฉบับที่ 10
แนวทางการทำ Digital transformation
The Power of Big Data for a new economy (Sample)
บทความ Robotics แนวโน้มใหม่สู่บริการเฉพาะทาง
IT Trends eMagazine Vol 3. No.9
Thailand software & software market survey 2016
Developing Business Blockchain Applications on Hyperledger
Digital transformation @thanachart.org
บทความ Big Data จากบล็อก thanachart.org
กลยุทธ์ 5 ด้านกับการทำ Digital Transformation

Java Programming [12/12] : Thread

  • 1. บทที่ 12 โปรแกรมแบบเธรด (Thread) อ.ธนิศ า เครือ ไวศยวรรณ คณะเทคโนโลยีส ารสนเทศ สถาบัน เทคโนโลยีพ ระจอมเกล้า เจ้า คุณ ทหารลาดกระบัง
  • 2. วัต ถุป ระสงค์  นิย ามความหมายของเธรด  แนะนำา องค์ป ระกอบของเธรด  แนะนำา วิธ ีก ารสร้า งคลาสแบบเธรดโดยการ สืบ ทอดมาจากคลาสทีช ื่อ Thread หรือ ่ implements อิน เตอร์เ ฟสทีช ื่อ Runnable ่  อธิบ ายขัน ตอนการทำา งานของโปรแกรมแบบเธรด ้  แนะนำา เมธอดต่า งๆทีเ กี่ย วข้อ งกับ การทำา งานของ ่ คลาส Thread  อธิบ ายการใช้ค ีย เ วิร ์ด synchronized ์ เพือ ป้อ งกัน ่ การผิด พลาดของการอ่า นข้อ มูล หรือ เขีย นข้อ มูล ที่ อาจเกิด ขึ้น จากโปรแกรมแบบเธรด
  • 3. ระบบปฏิบ ัต ิก ารแบบ Multitasking  ระบบปฏิบ ัต ิก ารแบบ Multitasking คือ ระบบ ปฏิบ ัต ิก ารทีอ นุญ าตให้ผ ู้ใ ช้ส ามารถส่ง โปรแกรม ่ ให้ร ะบบปฏิบ ัต ิก ารทำา งานได้ม ากกว่า หนึง ่ โปรแกรมพร้อ มกัน ซึ่ง โปรแกรมแต่ล ะโปรแกรมที่ รัน อยูใ นระบบปฏิบ ัต ิก ารจะสร้า ง process ขึ้น มา ่  ระบบปฏิบ ัต ิก ารแบบ Multitasking จะมี process หลายๆ process เข้า คิว รอการทำา งาน โดยระบบ ปฏิบ ัต ิก ารจะกำา หนดลำา ดับ ของการทำา งานของ process เอง
  • 4. โปรแกรมมัล ติเ ธรด  โปรแกรมมัล ติเ ธรดจะเป็น การทำา งานหลายงาน พร้อ มกัน โดยแต่ล ะงานจะเรีย กว่า เธรด ซึ่ง จะแตก ต่า งจาก process ทีท ำา งานภายใต้ร ะบบปฏิบ ัต ิ ่ การแบบ Multitasking ตรงที่ process แต่ล ะ process จะมีค วามเป็น อิส ระต่อ กัน แต่เ ธรดแต่ล ะ เธรดอาจใช้ข ้อ มูล ร่ว มกัน ซึ่ง เปรีย บเสมือ นซีพ ย ู ี จำา ลอง (Virtual CPU)  โปรแกรมแบบเธรดจะมีห ลัก การทำา งานทีแ ตกต่า ง ่ กัน ทั้ง นี้ข น อยูก ับ ระบบปฏิบ ัต ิก ารและจำา นวนซีพ ย ู ึ้ ่ ี
  • 5. โปรแกรมมัล ติเ ธรด  ในระบบคอมพิว เตอร์ท ม ซ พ ย ูห ลายตัว โปรแกรม ี่ ี ี ี แบบเธรดแต่ล ะโปรแกรมสามารถทีจ ะรัน พร้อ มกัน ่ ได้  ในระบบคอมพิว เตอร์ท ม ซ พ ย ูต ัว เดีย ว ี่ ี ี ี ระบบปฏิบ ัต ิ การจะเป็น ส่ว นทีจ ะจัด การตารางการทำา งานของ ่ โปรแกรมเธรด ซึง อาจแบ่ง เวลาการทำา งานของ ่ ซีพ ย ู ี
  • 6. องค์ป ระกอบของโปรแกรมแบบ เธรด  ซีพ ย ู ี คือ การจัด การทำา งานของโปรแกรมแบบ เธรด  ซอร์ด โค้ด คือ คลาสในภาษาจาวาทีเ ป็น คลาส ่ แบบเธรด  ออปเจ็ค คือ ออปเจ็ค ของคลาสแบบเธรด
  • 7. ออปเจ็ค แบบเธรด  โปรแกรมภาษาจาวาสามารถกำา หนดให้อ อปเจ็ค ของคลาสใดๆ ทำา งานเป็น แบบเธรดได้ ซึ่ง ก็จ ะ ทำา ให้ส ามารถรัน โปรแกรมของออปเจ็ค แบบเธรด หลายๆออปเจ็ค พร้อ มกัน ได้  ภาษาจาวาจะมีต ัว จัด ตารางเวลา (Thread Scheduler) ของออปเจ็ค แบบ เธรดเพือ จัด ่ ลำา ดับ การทำา งานของออปเจ็ค แบบเธรด  โปรแกรมบางประเภทจำา เป็น ต้อ งพัฒ นาเป็น แบบ เธรดอาทิเ ช่น • โปรแกรมภาพกราฟฟิก แบบเคลื่อ นไหว (Graphics Animation) • โปรแกรมนาฬิก า •
  • 8. การสร้า งคลาสแบบเธรด  โปรแกรมแบบเธรดในภาษาจาวาจะใช้ห ลัก การ ของการสร้า งออปเจ็ค ของคลาสแบบเธรดแล้ว เรีย กใช้เ มธอดเพื่อ ส่ง ให้อ อปเจ็ค ดัง กล่า วทำา งาน พร้อ มกัน  คลาสแบบเธรดในภาษาจาวาคือ คลาสทีส ืบ ทอดมา ่ จากคลาสทีช ื่อ Thread หรือ คลาสที่ implements ่ อิน เตอร์เ ฟส Runnable ออปเจ็ค ทีส ร้า งมาจากคลาส ่ แบบเธรดจะเรีย กว่า ออปเจ็ค แบบ runnable
  • 9. ตัว อย่า งโปรแกรม class PrintName { class PrintName { String name; String name; public PrintName(String n) { public PrintName(String n) { name = n; name = n; }} public void run() { public void run() { for(int i=0; i<100; i++) { for(int i=0; i<100; i++) { System.out.println(name); System.out.println(name); }} }} }} public class TestPrintName { public class TestPrintName { public static void main(String args[]) { public static void main(String args[]) { PrintName p1 = new PrintName("Thana"); PrintName p1 = new PrintName("Thana"); PrintName p2 = new PrintName("Somchai"); PrintName p2 = new PrintName("Somchai"); p1.run(); p1.run(); p2.run(); p2.run(); }} }}
  • 10. อธิบ ายตัว อย่า งโปรแกรม  โปรแกรมนี้เ ป็น โปรแกรมทีท ำา งานในรูป แบบปกติ ่ โดยคลาส PrintName มีเ มธอด run() ซึ่ง จะพิม พ์ ข้อ ความในคุณ ลัก ษณะ name จำา นวน 100 ครั้ง  คลาส TestPrintName จะสร้า งออปเจ็ค ของคลาส PrintName ขึ้น มาสองออปเจ็ค ทีช อ p1 และ p2 จาก ่ ื่ นัน จะเรีย กใช้เ มธอด run() เพือ พิม พ์ข ้อ ความออก ้ ่ มา  เนือ งจากโปรแกรมนีไ ม่ไ ด้เ ป็น โปรแกรมแบบเธรด ่ ้ ดัง นั้น ซีพ ีย จ ะทำา คำา สัง p1.run() ให้เ สร็จ ก่อ นแล้ว ู ่ จึง จะทำา คำา สั่ง p2.run()
  • 11. การ implements อิน เตอร์เ ฟส Runnable  คลาสแบบเธรดสามารถสร้า งได้โ ดยการ implements อิน เตอร์เ ฟส Runnable ซึ่ง เมธอดเดีย วที่ จะต้อ งเขีย นบล็อ กคำา สั่ง คือ เมธอด run() โดยมีร ูป แบบดัง นี้ public class ClassName implements Runnable { public void run(){ [statements] } }  คำา สั่ง ทีอ ยูใ นเมธอด run() ่ ่ คือ ชุด คำา สัง ทีต ้อ งการ ่ ่ ให้โ ปรแกรมทำา งานในลัก ษณะแบบเธรด โปรแกรมจาวาทีร ัน ออปเจ็ค ของคลาสแบบเธรด ่ ในลัก ษณะนีจ ะต้อ งมีก ารสร้า งออปเจ็ค ของคลาสที่ ้ ชื่อ Thread ก่อ น
  • 12. การ implements อิน เตอร์เ ฟส Runnable  Constructor ของคลาสทีช ื่อ Thread จะมี ่ argument เพือ รับ ออปเจ็ค ของคลาสที่ implements ่ อิน เตอร์เ ฟส Runnable โดยมีร ูป แบบดัง นี้ public Thread(Runnable obj)  ภายหลัง จากทีส ร้า งออปเจ็ค ของคลาสแบบเธรด ่ แล้ว เราสามารถจะสั่ง งานให้อ อปเจ็ค obj เริ่ม ทำา งานได้โ ดยการเรีย กใช้เ มธอด start() ทีอ ยูใ น ่ ่ คลาสทีช ื่อ Thread ่  คลาสทีช ื่อ Thread ่ จะลงทะเบีย นออปเจ็ค ดัง กล่า ว ลงในตัว จัด ตารางเวลา และเมือ ซีพ ย เ รีย กรัน ่ ี ู โปรแกรมของออปเจ็ค ดัง กล่า ว คำา สั่ง ในเมธอด run() จะถูก สั่ง งานตามลำา ดับ
  • 13. ตัว อย่า งโปรแกรม class PrintName implements Runnable { class PrintName implements Runnable { String name; String name; public PrintName(String n) { public PrintName(String n) { name = n; name = n; }} public void run() { public void run() { for(int i=0; i<100; i++) { for(int i=0; i<100; i++) { System.out.println(name); System.out.println(name); }} }} }} public class PrintNameThread { public class PrintNameThread { public static void main(String args[]) { public static void main(String args[]) { PrintName p1 = new PrintName("Thana"); PrintName p1 = new PrintName("Thana"); PrintName p2 = new PrintName("Somchai"); PrintName p2 = new PrintName("Somchai"); Thread t1 = new Thread(p1); Thread t1 = new Thread(p1); Thread t2 = new Thread(p2); Thread t2 = new Thread(p2); t1.start(); t1.start(); t2.start(); t2.start(); }} }}
  • 14. อธิบ ายตัว อย่า งโปรแกรม  ตัว อย่า งโปรแกรมนีเ ป็น การปรับ ปรุง คลาส ้ PrintName ให้เ ป็น คลาสแบบ เธรดโดยการ implements อิน เตอร์เ ฟส Runnable  โปรแกรม PrintNameThread สร้า งออปเจ็ค ของคลาส PrintName ขึ้น มาสองออปเจ็ค คือ p1 และ p2 ซึ่ง เป็น ออปเจ็ค แบบ runnable จากนัน โปรแกรมได้ส ร้า ง ้ ออปเจ็ค ของคลาส Thread คือ t1 และ t2 ทีม ซ อร์ด ่ ี โค้ด เดีย วกัน คือ PrintName แต่ม อ อปเจ็ค ต่า งกัน คือ ี p1 และ p2  เมธอด t1.start()และ t2.start()เป็น การส่ง ออป เจ็ค แบบเธรดเข้า ไปจองคิว กับ ตัว จัด ตารางเวลา
  • 15. การ extends คลาสที่ช อ ื่ Thread  คลาสแบบเธรดสามารถสร้า งได้โ ดยการสืบ ทอด คลาสทีช ื่อ Thread ซึง จะต้อ งมีก าร override ่ ่ เมธอด run() โดยมีร ูป แบบดัง นี้ public class ClassName extends Thread { public void run(){ [statements] } }  เราสามารถเรีย กใช้เ มธอด start()เพื่อ ลงทะเบีย น ออปเจ็ค ของคลาสดัง กล่า วในตัว จัด ตารางเวลาได้ โดยไม่จ ำา เป็น ต้อ งสร้า งออปเจ็ค ของคลาส Thread และเมือ ซีพ ย เ รีย กรัน โปรแกรมของออปเจ็ค คำา สั่ง ่ ี ู ในเมธอดแบบ overriden ที่ช อ run() จะถูก สัง งาน ื่ ่ ต่อ ไป
  • 16. ตัว อย่า งโปรแกรม class PrintName extends Thread {{ class PrintName extends Thread String name; String name; public PrintName(String n) {{ public PrintName(String n) name == n; name n; }} public void run() {{ public void run() for(int i=0; i<100; i++) {{ for(int i=0; i<100; i++) System.out.println(name); System.out.println(name); }} }} }} public class PrintNameThread {{ public class PrintNameThread public static void main(String args[]) {{ public static void main(String args[]) PrintName p1 == new PrintName(); PrintName p1 new PrintName(); PrintName p2 == new PrintName(); PrintName p2 new PrintName(); p1.run(); p1.run(); p2.run(); p2.run(); }} }}
  • 17. เปรีย บเทีย บวิธ ีก ารสร้า งคลาสแบบ เธรด  การสร้า งคลาสโดยการสืบ ทอดคลาสทีช ื่อ Thread ่ จะเป็น การเขีย นโปรแกรมทีส ั้น กว่า ่  การสร้า งคลาสโดย implements อิน เตอร์เ ฟส Runnable จะมีห ลัก การเชิง ออปเจ็ค ทีด ก ว่า ่ ี เนือ งจากคลาสดัง กล่า วไม่ใ ช่ค ลาสทีส ืบ ทอดมา ่ ่ จากคลาส Thread โดยตรง นอกจากนีย ง ทำา ให้ก าร ้ ั เขีย นโปรแกรมมีร ูป แบบเดีย วกัน เสมอ เพราะ คลาสในจาวาจะสืบ ทอดได้เ พีย งคลาสเดีย ว
  • 19. สถานะ New  เป็น สถานะเมือ มีก ารสร้า งออปเจ็ค ของคลาสแบบ ่ เธรด ก่อ นทีจ ะมีก ารเรีย กใช้เ มธอดทีช ื่อ ่ ่ start()
  • 20. สถานะ Runnable และสถานะ Running  Runnable เป็น สถานะที่อ อปเจ็ค แบบเธรดพร้อ มที่ จะทำา งาน ซึ่ง อาจเกิด จากการเรีย กใช้เ มธอด start() หรือ เกิด จากการกลับ มาจากสถานะที่ เป็น การบล็อ กเธรด  ออปเจ็ค แบบเธรดทีอ ยูใ นสถานะ Runnable จะ ่ ่ เข้า สูส ถานะ Running ซึ่ง เป็น สถานะทีซ พ ีย ร ัน คำา ่ ่ ี ู สั่ง ของออปเจ็ค แบบเธรด เมือ ตัว จัด ตารางเวลาจัด ่ เวลาทำา งานให้โ ดยจะทำา งานตามชุด คำา สัง ใน ่ เมธอด run()  ออปเจ็ค แบบเธรดจะหยุด การทำา งานและกลับ เข้า สู่ สถานะ Runnable อีก ครั้ง เมือ ตัว จัด ตารางเวลา ่ เปลี่ย นให้อ อปเจ็ค แบบเธรดอื่น ๆ ทีอ ยูใ นสถานะ ่ ่
  • 21. สถานะ Blocked  ออปเจ็ค แบบเธรดทีอ ยูใ นสถานะ ่ ่ Running อาจ ถูก บล็อ กแล้ว ย้า ยไปอยูใ นสถานะ Blocked ได้ ่ เนือ งจากเหตุก ารณ์ต ่า งๆดัง นี้ ่ • มีก ารเรีย กใช้เ มธอด sleep() • ออปเจ็ค แบบเธรดรอรับ การทำา งานที่เ ป็น อิน พุต หรือ เอาท์พ ุต • มีก ารเรีย กใช้เ มธอดที่ช ื่อ wait() • ออปเจ็ค แบบเธรดถูก เรีย กโดยเมธอด suspend()  ออปเจ็ค แบบเธรดทีอ ยูใ นสถานะ ่ ่ Blocked จะกลับ เข้า สูส ถานะ Runnable ได้อ ีก ครั้ง หนึง จาก ่ ่ เหตุก ารณ์ต ่า งๆดัง นี้ • เมื่อ หมดระยะเวลาการพัก ที่ก ำา หนดในเมธอด sleep() หรือ ถูก อิน เตอร์ร ับ • เมื่อ มีก ารส่ง ข้อ มูล อิน พุต หรือ เอาท์พ ุต • เมื่อ มีอ อปเจ็ค แบบเธรดตัว อื่น เรีย กเมธอด notify() หรือ
  • 22. สถานะ Dead  ออปเจ็ค แบบเธรดจะเข้า สู่ส ถานะ Dead เมือ สิน สุด ่ ้ การทำา งานเนือ งจากสิ้น สุด การทำา งานในชุด คำา สัง ่ ่ ของเมธอด run() หรือ เมือ มีก ารส่ง ออปเจ็ค ประเภท ่ Exception ทีไ ม่ไ ด้ม ก ารตรวจจับ (catch) ใน ่ ี เมธอด run()
  • 23. เมธอดของคลาส Thread  คลาสทีช ื่อ Thread ่ มีเ มธอดต่า งๆทีส ำา คัญ ดัง นี้ ่ • void run() เป็น เมธอดที่จ ะถูก เรีย กใช้เ มื่อ ซีพ ีย ูร ัน โปรแกรมออป เจ็ค แบบเธรด • void start() เป็น เมธอดที่เ รีย กใช้ง านเพื่อ กำา หนดให้อ อปเจ็ค แบบ เธรด เริ่ม ทำา งานโดยเข้า สู่ส ถานะ Runnable • void suspend() เป็น เมธอดที่ใ ช้ใ นการหยุด การทำา งานของออปเจ็ค แบบ เธรด เมธอดนี้ไ ม่ม ีก ารแนะนำา ให้ใ ช้ใ นภาษาจาวา ตั้ง แต่เ วอร์ช ั่น 1.2 เพื่อ ป้อ งกัน ไม่ใ ห้เ กิด เหตุก ารณ์ deadlock ที่จ ะกล่า วถึง ต่อ ไป • void resume() เป็น เมธอดที่ใ ช้ใ นการสั่ง ให้อ อปเจ็ค แบบเธรดกลับ เข้า
  • 24. เมธอดของคลาส Thread  คลาสทีช ื่อ Thread ่ มีเ มธอดต่า งๆทีส ำา คัญ ดัง นี้ ่ • static void sleep(long mills) เป็น เมธอดที่ก ำา หนดให้อ อปเจ็ค แบบเธรดที่อ ยู่ใ นสถานะ Running หยุด การทำา งานเป็น เวลา mills มิล ลิว ิน าที หรือ จนกว่า ถูก อิน เตอร์ร ับ • boolean isAlive() เป็น เมธอดที่ใ ช้ต รวจสอบว่า ออปเจ็ค แบบเธรดยัง มี สถานะ Running อยู่ห รือ ไม่ • void setPriority(int p) เป็น เมธอดที่ใ ช้ใ นการกำา หนดลำา ดับ ความสำา คัญ ขอ งออปเจ็ค แบบเธรด ซึ่ง จะมีค ่า ได้ร ะหว่า ง 1 ถึง 10 โดยที่ค ่า 10 เป็น ค่า สูง สุด • int getPriority() เป็น เมธอดที่ใ ช้ใ นการเรีย กดูค ่า ลำา ดับ ความสำา คัญ ขอ
  • 25. Synchronization  กรณีท อ อปเจ็ค แบบเธรดใช้ข ้อ มูล ร่ว มกัน อาจเกิด ี่ ปัญ หาทีเ รีย กว่า race condition ขึ้น ได้ ่  กรณีท อ อปเจ็ค แบบเธรดต่า งแย่ง กัน จัด การข้อ มูล ี่ ทำา ให้ไ ด้ข ้อ มูล ทีผ ิด พลาด ่
  • 26. ตัว อย่า งโปรแกรม public class BankSystemUnSync{ public class BankSystemUnSync{ public static void main(String[] args){ public static void main(String[] args){ final int NACCOUNTS = 10; final int NACCOUNTS = 10; final int INITIAL_BALANCE = 10000; final int INITIAL_BALANCE = 10000; Bank b = new Bank(NACCOUNTS, INITIAL_BALANCE); Bank b = new Bank(NACCOUNTS, INITIAL_BALANCE); int i; int i; for (i = 0; i < NACCOUNTS; i++) { for (i = 0; i < NACCOUNTS; i++) { Transfer t = new Transfer(b, i,INITIAL_BALANCE); Transfer t = new Transfer(b, i,INITIAL_BALANCE); t.setPriority(Thread.NORM_PRIORITY + i % 2); t.setPriority(Thread.NORM_PRIORITY + i % 2); t.start(); t.start(); }} }} }}
  • 27. ตัว อย่า งโปรแกรม class Bank{ class Bank{ public static final int NTEST = 10000; public static final int NTEST = 10000; private final int[] accounts; private final int[] accounts; private long ntransacts = 0; private long ntransacts = 0; public Bank(int n, int initialBalance) { public Bank(int n, int initialBalance) { accounts = new int[n]; accounts = new int[n]; for (int i = 0; i < accounts.length; i++) { for (int i = 0; i < accounts.length; i++) { accounts[i] = initialBalance; accounts[i] = initialBalance; }} ntransacts = 0; ntransacts = 0; }} public void transfer(int from, int to, int amount) { public void transfer(int from, int to, int amount) { if (accounts[from] < amount) { if (accounts[from] < amount) { return; return; }}
  • 28. ตัว อย่า งโปรแกรม accounts[from] -= amount; accounts[from] -= amount; accounts[to] += amount; accounts[to] += amount; ntransacts++; ntransacts++; if (ntransacts % NTEST == 0) { if (ntransacts % NTEST == 0) { test(); test(); }} }} public void test(){ public void test(){ int sum = 0; int sum = 0; for (int i = 0; i < accounts.length; i++){ for (int i = 0; i < accounts.length; i++){ sum += accounts[i]; sum += accounts[i]; }} System.out.println("Transactions:" + ntransacts System.out.println("Transactions:" + ntransacts + " Sum: " + sum); + " Sum: " + sum); }} public int size(){ public int size(){ return accounts.length; return accounts.length; }} }}
  • 29. ตัว อย่า งโปรแกรม class Transfer extends Thread{ class Transfer extends Thread{ private Bank bank; private Bank bank; private int fromAccount; private int fromAccount; private int maxAmount; private int maxAmount; public Transfer(Bank b, int from, int max) { public Transfer(Bank b, int from, int max) { bank = b; bank = b; fromAccount = from; fromAccount = from; maxAmount = max; maxAmount = max; }} public void run() { public void run() { try { try { while (!interrupted()) { while (!interrupted()) { int toAccount = (int)(bank.size() * Math.random()); int toAccount = (int)(bank.size() * Math.random()); int amount = (int)(maxAmount * Math.random()); int amount = (int)(maxAmount * Math.random()); bank.transfer(fromAccount, toAccount, amount); bank.transfer(fromAccount, toAccount, amount); Thread.sleep((int) (Math.random() * 10)); Thread.sleep((int) (Math.random() * 10)); }} }} catch(InterruptedException e) {} catch(InterruptedException e) {} }} }}
  • 30. ตัว อย่า งโปรแกรม class TransferThread extends Thread {{ class TransferThread extends Thread private Bank bank; private Bank bank; private int sourceAcct; private int sourceAcct; private int destAcct; private int destAcct; public TransferThread(Bank b,int s,int d) {{ public TransferThread(Bank b,int s,int d) bank == b; bank b; sourceAcct == s; sourceAcct s; destAcct == d; destAcct d; }} public void run() {{ public void run() try {{ try while (!interrupted()) {{ while (!interrupted()) bank.transfer(sourceAcct,destAcct); bank.transfer(sourceAcct,destAcct); sleep(1); sleep(1); }} }} catch (Exception e) {{ }} catch (Exception e) }} }}
  • 31. อธิบ ายตัว อย่า งโปรแกรม  เป็น ตัว อย่า งกรณีข องโปรแกรมจำา ลองระบบ ธนาคารซึ่ง จะมีค ลาส Bank ทีม บัญ ชีล ูก ค้า อยู่ 10 ่ ี บัญ ชีโ ดยมีย อดเงิน รวมของทุก บัญ ชีท ง สิ้น จำา นวน ั้ 100,000 บาท และมีเ มธอด transfer() ที่ใ ช้ใ นการ โอนเงิน ระหว่า งบัญ ชีห นึง ไปยัง อีก บัญ ชีห นึง โดย ่ ่ ใช้ค ำา สัง ่ • accounts[from] -= amount • accounts[to] += amount ตัว แปร from คือ หมายเลขบัญ ชีท ี่ต ้อ งการตัด โอนเงิน ไป ตัว แปร to คือ หมายเลขบัญ ชีท ี่ต ้อ งการรับ เงิน เข้า มา  คลาส TransferThread เป็น คลาสแบบเธรดทีม ี ่ เมธอด run() ซึ่ง เรีย กใช้อ อปเจ็ค ของคลาส Bank เพือ โอนเงิน ระหว่า งบัญ ชีใ ดๆแบบสุ่ม โดยจะ ่
  • 32. อธิบ ายผลลัพ ธ์ท ี่ไ ด้จ ากการรัน โปรแกรม  ตัว อย่า งผลลัพ ธ์ท ไ ด้จ ากการรัน โปรแกรมนี้ ี่ จะ เห็น ได้ว ่า เมือ รัน โปรแกรมไปได้ร ะยะหนึง จะมีผ ล ่ ่ รวมยอดเงิน ทีผ ิด พลาด ทั้ง นี้เ นื่อ งจากเกิด ปัญ หาที่ ่ เรีย กว่า race condition ซึง ออปเจ็ค แบบเธรด ่ แต่ล ะตัว อาจหยุด ทำา งานระหว่า งขั้น ตอนใดๆของ คำา สั่ง ในเมธอด run() เพือ ให้อ อปเจ็ค แบบเธรดตัว ่ อื่น ได้ท ำา งาน ซึ่ง คำา สั่ง แต่ล ะคำา สั่ง อาจมีข ั้น ตอน การทำา งานหลายขั้น เช่น คำา สัง ่ account[to] += amount จะไม่ใ ช่เ ป็น เพีย งคำา สั่ง เดีย วแต่จ ะมีข ั้น ตอนต่า งๆ ดัง นี้ • โหลด account[to] เข้า สู่ร ีจ ีส เตอร์ใ นซีพ ีย ู • บวกค่า ในรีจ ีสเตอร์ด ้ว ยค่า ของ amount
  • 33. คีย ์เ วิร ์ด synchronized  การทีอ อปเจ็ค แบบเธรดหยุด การทำา งานในขั้น ่ ตอนใดขั้น ตอนหนึง เพือ เปิด โอกาสให้อ อปเจ็ค ่ ่ แบบเธรดตัว อื่น ๆเข้า มาทำา งาน ก็อ าจจะทำา ให้ไ ด้ ผลลัพ ธ์ผ ิด พลาดได้  เราสามารถทีจ ะใช้ค ีย ์เ วิร ์ด synchronized ่ เพือ ล็อ ก ่ (lock) ชุด คำา สัง ที่ ออปเจ็ค แบบเธรดต้อ งกระทำา ่ พร้อ มกัน ไว้ไ ด้  กรณีน อ อปเจ็ค แบบเธรดจะไม่ห ยุด การทำา งาน ี้ ระหว่า งบล็อ กคำา สั่ง ทีถ ก ล็อ กไว้ และออปเจ็ค แบบ ่ ู เธรดตัว อื่น ๆจะต้อ งรอให้ซ ีพ ย ท ำา ชุด คำา สั่ง ทีถ ูก ี ู ่ ล็อ กไว้ใ ห้เ สร็จ ก่อ นแล้ว จึง เข้า มาทำา งานต่อ ได้ 
  • 35. การใช้ค ีย ์เ วิร ์ด synchronized  การใช้ค ีย เ วิร ์ด synchronized ์ เพือ ล็อ กคำา สั่ง ทำา ได้ ่ สองรูป แบบคือ • กำา หนดคีย ์เ วิร ์ด synchronized ที่เ มธอด • กำา หนดบล็อ กคีย ์เ วิร ์ด synchronized  ตัว อย่า งของการกำา หนดเมธอดทีช ื่อ transfer() ่ ให้ เป็น แบบ synchronized สามารถทำา ได้ด ัง นี้ public synchronized void transfer(int from, int to, int amount) { ... }
  • 36. เมธอด wait() และ notify()  เมธอด wait() และ notify() หรือ notifyAll() เป็น เมธอดทีใ ช้ก บ เมธอดหรือ บล็อ กคำา สั่ง ทีเ ป็น ่ ั ่ synchronized  เมธอด wait() จะมีผ ลให้อ อปเจ็ค แบบเธรดทีอ ยูใ น ่ ่ สถานะ Running กลับ เข้า สูส ถานะบล็อ กเพื่อ รอ ่ ให้อ อปเจ็ค แบบเธรดตัว อื่น ๆแจ้ง ให้ก ลับ เข้า สู่ สถานะ Runnable โดยใช้เ มธอด notify() หรือ notifyAll()
  • 37. ตัว อย่า งการใช้ค ีย ์เ วิร ์ด synchronized public class BankSystem { public class BankSystem { public static void main(String[] args) { public static void main(String[] args) { final int NACCOUNTS = 10; final int NACCOUNTS = 10; final int INITIAL_BALANCE = 10000; final int INITIAL_BALANCE = 10000; Bank b = new Bank(NACCOUNTS, INITIAL_BALANCE); Bank b = new Bank(NACCOUNTS, INITIAL_BALANCE); int i; int i; for (i = 0; i < NACCOUNTS; i++) { for (i = 0; i < NACCOUNTS; i++) { Transfer t = new Transfer(b, i, INITIAL_BALANCE); Transfer t = new Transfer(b, i, INITIAL_BALANCE); t.setPriority(Thread.NORM_PRIORITY + i % 2); t.setPriority(Thread.NORM_PRIORITY + i % 2); t.start(); t.start(); }} }} }}
  • 38. ตัว อย่า งการใช้ค ีย ์เ วิร ์ด synchronized class Bank { class Bank { public static final int NTEST = 10000; public static final int NTEST = 10000; private final int[] accounts; private final int[] accounts; private long ntransacts = 0; private long ntransacts = 0; public Bank(int n, int initialBalance) { public Bank(int n, int initialBalance) { accounts = new int[n]; accounts = new int[n]; for (int i = 0; i < accounts.length; i++) { for (int i = 0; i < accounts.length; i++) { accounts[i] = initialBalance; accounts[i] = initialBalance; }} ntransacts = 0; ntransacts = 0; }} public synchronized void transfer(int from, int to, int public synchronized void transfer(int from, int to, int amount) { amount) { try{ try{ while (accounts[from] < amount){ while (accounts[from] < amount){ wait(); wait(); }}
  • 39. ตัว อย่า งการใช้ค ีย ์เ วิร ์ด synchronized accounts[from] -= amount; accounts[from] -= amount; accounts[to] += amount; accounts[to] += amount; ntransacts++; ntransacts++; notifyAll(); notifyAll(); if (ntransacts % NTEST == 0) { if (ntransacts % NTEST == 0) { test(); test(); }} } catch(InterruptedException e) {} } catch(InterruptedException e) {} }} public synchronized void test() { public synchronized void test() { int sum = 0; int sum = 0; for (int i = 0; i < accounts.length; i++){ for (int i = 0; i < accounts.length; i++){ sum += accounts[i]; sum += accounts[i]; }} System.out.println("Transactions:" + ntransacts System.out.println("Transactions:" + ntransacts + " Sum: " + sum); + " Sum: " + sum); }}
  • 40. ตัว อย่า งการใช้ค ีย ์เ วิร ์ด synchronized public int size(){ public int size(){ return accounts.length; return accounts.length; }} }} class Transfer extends Thread{ class Transfer extends Thread{ private Bank bank; private Bank bank; private int fromAccount; private int fromAccount; private int maxAmount; private int maxAmount; public Transfer(Bank b, int from, int max){ public Transfer(Bank b, int from, int max){ bank = b; bank = b; fromAccount = from; fromAccount = from; maxAmount = max; maxAmount = max; }}
  • 41. ตัว อย่า งการใช้ค ีย ์เ วิร ์ด synchronized public void run() { public void run() { try { try { while (!interrupted()) { while (!interrupted()) { int toAccount = (int)(bank.size() * Math.random()); int toAccount = (int)(bank.size() * Math.random()); int amount = (int)(maxAmount * Math.random()); int amount = (int)(maxAmount * Math.random()); bank.transfer(fromAccount, toAccount, amount); bank.transfer(fromAccount, toAccount, amount); Thread.sleep(1); Thread.sleep(1); }} }} catch(InterruptedException e) {} catch(InterruptedException e) {} }} }}
  • 42. Deadlock  ในกรณีท อ อปเจ็ค แบบเธรดทุก ออปเจ็ค ถูก เรีย กใช้ ี่ คำา สั่ง wait() ทัง หมดโดยไม่ม อ อปเจ็ค ใดสามารถ ้ ี เรีย กคำา สั่ง notify() หรือ notifyAll()ได้ จะเป็น กรณีท อ อปเจ็ค แต่ล ะตัว รอการปลดล็อ กจากกัน ี่ และกัน จึง ทำา ให้เ กิด สถานการณ์ท เ รีย กว่าี่ deadlock ซึ่ง จะทำา ให้ไ ม่ม ก ารทำา งานใดๆเกิด ขึ้น ี  ตัว อย่า งเช่น ถ้า คลาส Bank ของโปรแกรมทีผ ่า นมา ่ มีบ ัญ ชีเ พีย งสองบัญ ชีโ ดยบัญ ชีท ห นึ่ง มีย อดเงิน ี่ 2,000 บาท และบัญ ชีท ส องมีย อดเงิน 3,000 บาท ี่ และถ้า ออปเจ็ค แบบเธรดตัว ทีห นึง มีค ำา สั่ง ่ ่ transfer()เพือ โอนเงิน จากบัญ ชีท ห นึง ไปยัง บัญ ชีท ี่ ่ ี่ ่ สองเป็น เงิน 3,000 บาท และออปเจ็ค แบบเธรดตัว ทีส องมีค ำา สัง transfer()เพือ โอนเงิน จากบัญ ชีท ี่ ่ ่ ่ สองไปยัง บัญ ชีท ห นึง เป็น เงิน 4,000 บาท กรณีน ี้ ี่ ่
  • 44. สรุป เนื้อ หาของบท  เธรดจะแตกต่า งจาก process ทีท ำา งานภายใต้ ่ ระบบปฏิบ ัต ิก ารแบบ Multitasking ตรงที่ process แต่ล ะ process จะมีค วามเป็น อิส ระต่อ กัน แต่เ ธรดแต่ล ะเธรดอาจใช้ข ้อ มูล ร่ว มกัน ซึ่ง เปรีย บเสมือ นซีพ ย จ ำา ลอง (Virtual CPU) ี ู  เธรดประกอบไปด้ว ยซีพ ย ู ี ซอร์ด โค้ด และออปเจ็ค  คลาสแบบเธรดในภาษาจาวาคือ คลาสทีส ืบ ทอดมา ่ จากคลาสทีช ื่อ Thread หรือ คลาสที่ ่ implements อิน เตอร์เ ฟส Runnable  ภายในคลาสแบบเธรดจะต้อ งมีเ มธอด run() ทีไ ม่ม ี ่ การรับ argument ใดๆเข้า มา
  • 45. สรุป เนื้อ หาของบท  สถานะของเธรดอาจจะเป็น New, Runnable, Running, Blocked หรือ Dead การเข้า สู่ส ถานะ Running จะขึ้น อยูก บ ตัว จัด ตารางเวลา ่ ั  เราสามารถทีจ ะใช้ค ีย ์เ วิร ์ด ทีช ื่อ synchronized ่ ่ เพือ่ ล็อ ก (lock) ชุด คำา สัง ที่ ่ ออปเจ็ค แบบเธรดต้อ ง กระทำา พร้อ มกัน ไว้ไ ด้  Deadlock หมายถึง การทีอ อปเจ็ค แต่ล ะตัว รอการ ่ ปลดล็อ กจากกัน และกัน ทำา ให้ไ ม่ม ก ารทำา งานใดๆ ี เกิด ขี้น
  • 46. แบบฝึก หัด  ข้อ ที่ 1 • ทดลองเขีย นโปรแกรมนาฬิก าแบบดิจ ิต อล โดยให้ม ี การทำา งานแบบ Thread