บทที่ 8

ทรดคืออะไร

เทรด คือ ส่วนของกระบวนการ (Process) ถ้าไม่มีกระบวนการก็ไม่มีเทรด เทรด ค่ือ ส่วนหน่วยย่อยที่สุด ที่มีองค์ประกอบครบถ้วนพร้อมที่จะนำไปให้หน้อยประมวลผลกลางประมวลได้ เรียกกระบวนการนี้ว่า 
"การดเอ็กซีคิวต์ ( execute) เทรดนั้นคือความเป็นอิสสระโดยสามารถนำไปทำการเอ็กซีคิวต์ได้โดยไม่ขึ้นกับการกระบวนการหรือเทรออื่น สิ่งที่เราจำเป็นต้องรู้เกี่ยวกับเทรด คือ การแบ่งเทรดออกจากกระบวนการการสร้างเทรดการแบ่งกันทำงาน ลำดับ ความสำคัญของเทรด และการทำงานที่สอดคล้องกันของเทรดเป็นที่กันดีว่า กระบวนการนั้นเรียกว่า "Heavy Weight Process" แต่ถ้าแตกออกเป็นเทรด

ประเภทของเทรด

เนื่องจากเทรดนั้นประกอบไปด้วยส่วนสำคัญที่ซีพียูสามารถประมวลผลได้ คือ เทรดของผู้ใช้งาน (User Thread ) ซึ่งถูกสร้างขึ้นมา และส่วนของเทรดในคอร์เนล (Kernel Thread) ที่พร้อมจะเข้าสู่การประมวลผลหรือเอ็กซีคิวต์ หากนำมาเขียนภาพจำลองจะมีลักษณะดังนี้

1.หมายเลขเทรด
2.เลขนับคำสั่งโปรแกรม
3.รีจิสเตอร์ที่เก็บค่าระหว่างเอ็กซีคิวต์
4.สแต็ก



ข้อดีของเทรด (Thread)

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

วงจรชีวิตรของเทรดในภาษาจาวา

โดยทั่วไปวงจรชีวิตรของภาษาจาวานั้นหมายถึง Servlets, Applets และ Threads .ในที่นี้จะกล่าวถึงสถานะของเทรดเท่านั้น โดยจะแบ่งสถานะออกเป้น 4 สถานะคือ 
1.การสร้างเทรดขึ้นมาใหม่ (New Thead State)
2.การรันหรือเอ็กซีคิวต์ (Runnable State)
3.การบล็อก (Blocked State)
4.การสิ้นสุดของเทรด (Dead State)



จากไดอะแกรมแสดงวงจรชีวิตรของสถานะของเทรด จะเห็นว่า เมื่อสร้างเทรดขึ้นมาด้วยการสร้างตัวแปรออปเจกต์ Threadsample t=new threadsample () แล้วเรียกเมธอด T.start() หากเทรด
หยุดทำการทำงาน

การใช้ Exception ในเทรด 

เนื่องจากว่าเทรดได้รับการถ่ายทอดมาจากเพ็จเก็จ java ซึ่งหลักการทำงานั้นมีขั้นตอนหรือสถนานะหลากหลาย ดังนั้น จาวา ได้สร้าง exception เพื่อตรวจสอบข้อผิดพลาดที่อาจเกิดขึ้น 2 คลาส คือ 
1.lnterruptedException : มีการแจ้งไปยังเทรดที่อยู่ในสถานะ รอคอย (waiting) หรือหลับไหลหรือถูกปลุกขึ้นมา
2.illegalStateException : มีการแจ้งไปยังเทรดที่มีคำสั่งให้มีการเริ่มทำงานอีกซึ่งในความเป็นจริงนั้นมีการทำงานอยู่แล้่ว

การสร้างเทรด (Thread Creation)

เราทราบมาก่อนหน้านี้แล้วว่า เทรดนั้นไม่มีโครงสร้างซับซ้อนโดยหน่วยประมวลผลกลางสามารถ
ประมวลผลได้ จะขอยกตัวอย่างการทำงานของคลาส 2 คลาสคือ ThreadOne และ ThreadTwo
ที่มีคำสั่งให้แสดงผลในรอบเวลาที่ต่างๆกันด้วยการใช้เมธอด Sleep() ส่วนคลาสที่สามคือ Threadsample
ทำหน้าที่เรียกใช้งานจากคลาสทั้งสองเพื่อให้แสดงออกมา

ตัวอย่างที่ 8.1



ตารางการทำงานของเทรดในภาษาจาวา 

(Java Thread Schedulin)

ในโลกของความเป็นจริงไม่มีเพียงโปรแกรมเดียวที่สร้างเทรดขึ้นมา ภาษาจาวาไม่ได้เอ็กซีคิวต์เพียงลำพัง จาวาได้ให้ความสำคัญกับการทำงานของระบบปฎิบัติการและกำหนดเวลาการทำงานให้หน่วยประมวลผลกลางเพื่อเฝ้าดูเทรดที่สร้างขึ้นเรียกว่า "ตารางการทำงาของเทรด (Thread Scheduler)"
เพื่อรักษาลำดับการทำงานของเทรดซึ่งควรให้ความสำคัญก่อนหรือหลัง ซึ่งจะมีอัลกอริทึมที่ทำหน้าที่จัดการโดยเฉพาะถ้าเราแตกเทรดออกมามากมายไว้ที่หนึ่้งที่เทรดอาจมีลำดับความสำคัญแตกต่างกัน เมื่อมีคำสั่งเมธอด มันจะทำการชี้ไปยังเทรดที่รอคอยการเอ็กซีคิวต์โดยใช้หลักพิจารณา

เทรดที่สำคัญในภาษาจาวา

>>Main คือ เทรดหนึ่งที่ใช้กับ JVM การเอ็กคิวต์จะเริ่มต้นด้วย Main Thread
>>Garbage Collector เป็น Daemon เทรดซึ่งจะทำหน้าที่ตอบสนองการทำงานก่อนเทรดอื่นใด เช่น
การรัน Eclipse จะเกิดขึ้นได้นั้นจะต้องรัน JDK หรือ JRE เสียก่อน
>>Event Dispatcher คือ เทรดที่จะคอยดูเหตุการณ์ โดยเหมือนกันกับการเฝ้าฟังเหตุการณ์ของ
ปุ่มว่ามีการคลิกหรือยังแต่นี่คือเทรดที่คอยดูว่ามีการร้องขออะไรมายังเทรดต่างๆ บ้าง
>>Timer เป็นเทรดที่รับผิดชอบเรื่องเวลาเทรด sleep ()
เมื่อเทรดเริ่มต้นเมธอด Start()

วิธีการสร้างเทรด (Thread Spawning)

เราสามารถสร้างเทรดสองวิะีต่อไปนี้
1. การสืบทอดคลาสเทรดด้วยการ Extends Thread
2. ทำการ Implements อินเตอร์เฟส Runnable

ตัวอย่างที่ 8.2


ผลการรันโปรแกรมตัวอย่างที่ 8.2


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

การทำงานให้สอดคล้องกันของเทรด(Thread Synchchronization)

   โดยทั่วไปแล้วเทรดหนึ่งเทรดจะใช้ทรัพยากรของตนเองหนึ่งตัว แต่ในบางครั้งอาจมีเทรดหลายตัวืฃที่จะเข้ามาใช้ทรัพยากรพร้อมกัน เรียกวว่า Multiple Threads Access หรือ Share ซึ่งอาจเกิดภปัยหาภายในการใช้งานได้ เช่น เทรดตัวที่ 1 และ 2 คือครองทรัพยากรตัวเดียวกันแต่เทรดตัวที่ 1 ทำงานเสร็จก่อนจะต้องคืนทรัพยากรสู่ระบบ ในขณะที่เทรดตัวที่ 2 ยังทำงานไม่เสร็จ หากคืนสู่ระบบไปแล้วทำให้เทรดตัวที่ 2 ไม่สามารถทำงานได้
   เพื่อหลีกเลี่ยงปัญหาดังกล่าวจึงต้องมีวิธีช่วยให้การทำงานสอดคล้องกันเรียกว่า Synchronization ทรัพยากรแบบต่างๆ ดดยข้อดีของการทำแบบนี้ คือ มีเทรดเพียงหนึ่งเทรดเท่านั้นที่อนุณาตใฟ้เข้าถึงทรัพยากรได้โดยที่เทรดอื่นจะต้องเข้าคิวรอจนกว่าเทรดนั้นจะทำงานเสร็จเสียก่อน ซึ่งการทำงานแบบนี้เป็นช่องทางให้เกิดการสื่อสารระหว่างเทรดที่ เรียกว่า (Inter-thread Communication) เช่น การเรียกใช้เมธอดเป็นjoin() ในโค้ดเพื่อให้ทำงานอย่างสอดคล้องกัน การใช้วิธีนี้จะทำให้โปรแกรมของเราช้าเพราะว่ามีเฉพาะเทรดเดียวเท่านั้นที่ใช้งานอยู่ นักออกแบบจึงใช้วิะี Synchronize เฉพาะส่วนที่มีความสำคัญ และที่วิกฤติกว่าและจะไม่ทำการ Synchronize โดยไม่จำเป็น ไม่ขอกล่าวละเอียดในขั้นพื้นฐานนี้ ยังมีสิ่งที่เกี่ยวข้องกับเทรดอีกมากดดยจะศึกษาและทำความเข้าใจได้ในหนังสือระบบปฏิบัติการในเชิงลึกที่เกี่ยวข้องกับเทรด

สตรีมไอโอ (Stream I/O)

สตรีม หมายถึง ออปเจกต์สมมติที่มีคล้ายกับท่อ ภายในจะมีข้อมูล (Bytes) ที่เรียงลำดับกันแบบเรียงหนึ่ง
การใช้งานสตรีม (Stream) จะต้องให้ปลายแต่ละข้างของสตรีมต่อกับ อุปกรณ์ Input หรือ output ของข้อมูลโดยประเภทของ Stream แบ่งออกเป็น 2 ประเภท
>>Input stream เราจะเรียกว่า "แหล่งข้อมูลสตรีมนำเข้า (Source Stream)"
>>Output Stream เราจะเรียกว่า "แหล่งข้อมูลสตรีมแสดงผล (Sink Stream)"
                                       
8.4 อินพุตสตรีม

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

การอ่าน เขียนข้อมูลเป็นไบต์ (Byte)
การอ่านและเขียนข้อมูลเป็นไบต์นั้นเป็นการอ่านและเขียนข้อมูลจากตัวอักษร โดยตรงตามจำนวนไบต์
ที่ปรากฎดดยอ้างอิงรหัส ASCLL เช่น ตัวเป็นการอ่านและเขียนจากไฟล์ขึ้นอยู่กับทิศทาง การอ่านและเขียน ซึ่งทำหน้าที่เป็น Source และ Sink
8.5 การอ่านเขียนข้อมูลเป็น ไบต์

การอ่านค่าจากอินพุต (input reader) ด้วย Read Metbod
                 
ตัวอย่างที่ 8.4


การเขียน (Output Writer) ด้วย Write Metbod

    ตัวอย่างที่8.5

ผลการรันโปรแกรมตัวอย่างที 8.5

การอ่านและเขียนเป็น Cbaracter และ String
การอ่านเขียนข้อมูลแบบนี้อาศัยผุ้ช่วย คือ คลาส Reader และ Writer ฉะนั้นจึงต้องทำการประกาศตัวแปรออปเจกต์มาเพื่อให้สามารถนำไปใช้งานได้สะดวกดังรูป

                       
รุปที่ 8.6 การอ่านเขียนข้อมูลแบบตัวอักษรและชุดตัวอักษร

การอ่านและเขียนด้วยวิธีนี้เป็นวิธีการทำงานผ่านคลาสที่ทำหน้าที่ในการจัดการโดยโฉพาะ คือ จาวาได้เตรียมไว้แล้วเพียงแต่เราจะต้องใช้ความรู้พื้นฐานในการเขียนโปรแกรมเชิงวัตถุ และนำไปใช้ให้ถูกต้องดดยมีคลาสสองคลาสที่อยู่ในแพ็คเกจ java.io คือ InputStreamReader ทำหน้าที่ในการอ่าน เช่น การใช้ System.in และ OutputStreamWriter ทำหน้าที่ในการเขียน เช่น System.out ซึ่งวิธี การดังกล่าวนี้จะมีส่วนที่เกี่ยวข้องกับการจัดการสตรีม ด้วยขั้นตอนที่กำหนดตามโครงสร้างของคลาสโดยทั่วไปก็จะมีความคล้ายคลึงกับการอ่านเขียนเป็นไปต์แต่มีคลาสที่รับผิดชอบแตกต่างกัน

ตัวอย่าง การเขียนด้วย InputStreamReader

 ตัวอย่างที่ 8.6

ผลการรันโปรแกรมตัวอย่างที่ 8.6

ตัวอย่าง การเขียนด้วย OutputStream Writer
                       
       ตัวอย่างที่ 8.7

ผลการรันโปรแกรมตัวอย่างที่ 8.7


ความคิดเห็น