แก้ไขปัญหาโดยมัลติเธรด
มัลติเธรดถูกประดิษฐ์ขึ้นเพื่อบรรลุวัตถุประสงค์สำคัญสองประการ:-
ทำหลายอย่างในเวลาเดียวกัน
ในตัวอย่างข้างต้น ด้ายต่างๆ (สมาชิกในครอบครัว) ดำเนินการหลายอย่างพร้อมกัน: พวกเขาล้างจาน ไปที่ร้าน และเก็บข้าวของ
เราสามารถเสนอตัวอย่างที่เกี่ยวข้องกับการเขียนโปรแกรมมากขึ้น สมมติว่าคุณมีโปรแกรมที่มีส่วนติดต่อผู้ใช้ เมื่อคุณคลิก 'ดำเนินการต่อ' ในโปรแกรม การคำนวณบางอย่างควรเกิดขึ้น และผู้ใช้ควรเห็นหน้าจอต่อไปนี้ หากดำเนินการเหล่านี้ตามลำดับ โปรแกรมจะหยุดทำงานหลังจากที่ผู้ใช้คลิกปุ่ม 'ดำเนินการต่อ' ผู้ใช้จะเห็นหน้าจอที่มีหน้าจอปุ่ม 'ดำเนินการต่อ' จนกว่าโปรแกรมจะทำการคำนวณภายในทั้งหมดและไปถึงส่วนที่มีการรีเฟรชอินเทอร์เฟซผู้ใช้
ฉันเดาว่าเราจะรอสองสามนาที!
หรือเราอาจปรับปรุงโปรแกรมของเรา หรืออย่างที่โปรแกรมเมอร์พูดว่า 'ขนานกัน' มาทำการคำนวณของเราบนเธรดหนึ่งและวาดอินเทอร์เฟซผู้ใช้บนเธรดอื่น คอมพิวเตอร์ส่วนใหญ่มีทรัพยากรเพียงพอที่จะทำเช่นนี้ หากเราใช้เส้นทางนี้ โปรแกรมจะไม่ค้างและผู้ใช้จะย้ายไปมาระหว่างหน้าจอได้อย่างราบรื่นโดยไม่ต้องกังวลกับสิ่งที่เกิดขึ้นภายใน หนึ่งไม่รบกวนอื่น ๆ :)
-
ทำการคำนวณได้รวดเร็วยิ่งขึ้น
ทุกอย่างง่ายกว่ามากที่นี่ หากโปรเซสเซอร์ของเรามีหลายคอร์ และโปรเซสเซอร์ส่วนใหญ่ในปัจจุบันมี คอร์หลายตัวสามารถจัดการรายการงานของเราพร้อมกันได้ เห็นได้ชัดว่า หากเราต้องดำเนินการ 1,000 งานและแต่ละงานใช้เวลา 1 วินาที หนึ่งคอร์สามารถทำงานเสร็จภายใน 1,000 วินาที สองคอร์ใน 500 วินาที สามคอร์ใน 333 วินาที เป็นต้น
public class MyFirstThread extends Thread {
@Override
public void run() {
System.out.println("I'm Thread! My name is " + getName());
}
}
ในการสร้างและเรียก ใช้ เธรด เราจำเป็นต้องสร้างคลาส ทำให้มันสืบทอดjava.lang คลาส เธรดและแทนที่เมธอดrun () ข้อกำหนดสุดท้ายนั้นสำคัญมาก มันอยู่ใน เมธอด run()ที่เรากำหนดตรรกะสำหรับเธรดของเราเพื่อดำเนินการ ตอนนี้ ถ้าเราสร้างและรันอินสแตนซ์ของMyFirstThread เมธอด run ()จะแสดงบรรทัดที่มีชื่อ: เมธอด getName()จะแสดงชื่อ 'ระบบ' ของเธรด ซึ่งกำหนดโดยอัตโนมัติ แต่ทำไมเราถึงพูดอย่างไม่แน่นอน? มาสร้างมันขึ้นมากันเถอะ!
public class Main {
public static void main(String[] args) {
for (int i = 0; i < 10; i++) {
MyFirstThread thread = new MyFirstThread();
thread.start();
}
}
}
เอาต์พุตคอนโซล: I'm Thread! ฉันชื่อเธรด-2 ฉันชื่อเธรด! ฉันชื่อเธรด-1 ฉันชื่อเธรด! ฉันชื่อเธรด-0 ฉันชื่อเธรด! ฉันชื่อเธรด-3 ฉันชื่อเธรด! ฉันชื่อเธรด-6 ฉันชื่อเธรด! ฉันชื่อเธรด-7 ฉันชื่อเธรด! ฉันชื่อเธรด-4 ฉันชื่อเธรด! ฉันชื่อเธรด-5 ฉันชื่อเธรด! ฉันชื่อเธรด-9 ฉันชื่อเธรด! ชื่อของฉันคือ Thread-8 มาสร้างเธรด 10 เธรด ( วัตถุ MyFirstThreadซึ่งสืบทอดThread ) และเริ่มต้นโดยการเรียกเมธอดstart()ในแต่ละวัตถุ หลังจากเรียกใช้เมธอดstart()ตรรกะในเมธอดrun()จะถูกดำเนินการ หมายเหตุ:ชื่อเธรดไม่เรียงตามลำดับ เป็นเรื่องแปลกที่พวกเขาไม่ได้เรียงตามลำดับ:, เธรด-1 , เธรด-2และอื่นๆ? สิ่งที่เกิดขึ้นนี้เป็นตัวอย่างหนึ่งของเวลาที่การคิดแบบ 'ตามลำดับ' ไม่เข้าท่า ปัญหาคือเราได้ให้คำสั่งในการสร้างและเรียกใช้ 10 เธรดเท่านั้น ตัวกำหนดตารางเวลาของเธรดซึ่งเป็นกลไกของระบบปฏิบัติการพิเศษ ตัดสินใจสั่งการดำเนินการ การออกแบบที่แม่นยำและกลยุทธ์การตัดสินใจเป็นหัวข้อสำหรับการสนทนาเชิงลึกที่เราจะไม่ลงลึกในตอนนี้ สิ่งสำคัญที่ต้องจำไว้คือโปรแกรมเมอร์ไม่สามารถควบคุมลำดับการดำเนินการของเธรดได้ เพื่อให้เข้าใจถึงความรุนแรงของสถานการณ์ ให้ลองเรียกใช้เมธอด main() ในตัวอย่างข้างต้นอีกสองสามครั้ง เอาต์พุตคอนโซลในการเรียกใช้ครั้งที่สอง: ฉันด้าย! ฉันชื่อเธรด-0 ฉันชื่อเธรด! ฉันชื่อเธรด-4 ฉันชื่อเธรด! ฉันชื่อเธรด-3 ฉันชื่อเธรด! ฉันชื่อเธรด-2 ฉันชื่อเธรด! ฉันชื่อเธรด-1 ฉันชื่อเธรด! ฉันชื่อเธรด-5 ฉันชื่อเธรด! ฉันชื่อเธรด-6 ฉันชื่อเธรด! ฉันชื่อเธรด-8 ฉันชื่อเธรด! ฉันชื่อเธรด-9 ฉันชื่อเธรด! ชื่อของฉันคือ Thread-7 Console เอาต์พุตจากการเรียกใช้ครั้งที่สาม: I'm Thread! ฉันชื่อเธรด-0 ฉันชื่อเธรด! ฉันชื่อเธรด-3 ฉันชื่อเธรด! ฉันชื่อเธรด-1 ฉันชื่อเธรด! ฉันชื่อเธรด-2 ฉันชื่อเธรด! ฉันชื่อเธรด-6 ฉันชื่อเธรด! ฉันชื่อเธรด-4 ฉันชื่อเธรด! ฉันชื่อเธรด-9 ฉันชื่อเธรด! ฉันชื่อเธรด-5 ฉันชื่อเธรด! ฉันชื่อเธรด-7 ฉันชื่อเธรด! ฉันชื่อเธรด-8
ปัญหาที่เกิดจากมัลติเธรด
ในตัวอย่างของเรากับหนังสือ คุณเห็นว่าการทำงานแบบมัลติเธรดช่วยแก้ปัญหาที่สำคัญมากและทำให้โปรแกรมของเราเร็วขึ้นได้ มักจะเร็วกว่าหลายเท่า แต่มัลติเธรดถือเป็นหัวข้อที่ยาก แท้จริงแล้วหากใช้ไม่ถูกต้องจะสร้างปัญหาแทนที่จะแก้ไข เมื่อฉันพูดว่า 'สร้างปัญหา' ฉันไม่ได้หมายความในแง่ที่เป็นนามธรรม มีปัญหาเฉพาะสองประการที่มัลติเธรดสามารถสร้างได้: การหยุดชะงักและสภาวะการแย่งชิง การหยุดชะงักคือสถานการณ์ที่หลายเธรดกำลังรอทรัพยากรที่แต่ละอื่น ๆ ถือครองอยู่ และไม่มีเธรดใดที่สามารถรันต่อไปได้ เราจะพูดถึงเรื่องนี้มากขึ้นในบทเรียนต่อๆ ไป ตัวอย่างต่อไปนี้จะเพียงพอสำหรับตอนนี้:
- Thread-1 หยุดโต้ตอบกับ Object-1 และสลับไปยัง Object-2 ทันทีที่ Thread-2 หยุดโต้ตอบกับ Object-2 และสลับไปยัง Object-1
- Thread-2 หยุดโต้ตอบกับ Object-2 และสลับไปยัง Object-1 ทันทีที่ Thread-1 หยุดโต้ตอบกับ Object-1 และสลับไปยัง Object-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();
}
}
}
ตอนนี้ลองนึกภาพว่าโปรแกรมมีหน้าที่ควบคุมหุ่นยนต์ที่ทำอาหาร! Thread-0 นำไข่ออกจากตู้เย็น หัวข้อ 1 เปิดเตา Thread-2 รับกระทะและวางบนเตา หัวข้อที่ 3 จุดเตา หัวข้อ 4 เทน้ำมันลงในกระทะ กระทู้ที่ 5 แบ่งไข่และเทลงในกระทะ Thread-6 โยนเปลือกไข่ลงถังขยะ Thread-7 นำไข่ที่สุกแล้วออกจากเตา Thread-8 วางไข่ที่ปรุงแล้วลงบนจาน กระทู้-9 ล้างจาน. ดูผลลัพธ์ของโปรแกรมของเรา: เธรดที่ดำเนินการ: เธรด-0 เธรดที่ดำเนินการ: เธรด-2 เธรดที่ดำเนินการ เธรด-1 เธรดที่ดำเนินการ: เธรด-4 เธรดที่ดำเนินการ: เธรด-9 เธรดที่ดำเนินการ: เธรด-5 เธรดที่ดำเนินการ: เธรด-8 เธรด ดำเนินการ: เธรด-7 เธรดที่ดำเนินการ: เธรด-3 นี่เป็นกิจวัตรตลกหรือไม่? :) และทั้งหมดเป็นเพราะการทำงานของโปรแกรมของเราขึ้นอยู่กับลำดับการดำเนินการของเธรด ห้องครัวของเรากลายเป็นนรกและหุ่นยนต์ที่บ้าคลั่งทำลายทุกสิ่งรอบตัวด้วยการละเมิดลำดับที่จำเป็นเพียงเล็กน้อย นี่เป็นปัญหาทั่วไปในการเขียนโปรแกรมแบบมัลติเธรด คุณจะได้ยินเกี่ยวกับเรื่องนี้มากกว่าหนึ่งครั้ง ในการสรุปบทเรียนนี้ ฉันขอแนะนำหนังสือเกี่ยวกับมัลติเธรด 
GO TO FULL VERSION