JavaRush /จาวาบล็อก /Random-TH /ชื่นชมเวลาด้วยลำธาร
Andrei
ระดับ

ชื่นชมเวลาด้วยลำธาร

เผยแพร่ในกลุ่ม

คำนำ. ลุงเพชร

สมมุติว่าเราต้องการเติมน้ำหนึ่งขวด มีขวดและน้ำประปาของลุงเพชรไว้ให้บริการ วันนี้ลุงเพชรยาได้ติดตั้ง faucet ใหม่ และเขาก็ชื่นชมความสวยงามของมันอยู่เสมอ ก่อนหน้านั้นเขาใช้แค่ก๊อกน้ำเก่าที่อุดตัน ดังนั้นเส้นขวดจึงใหญ่มาก หลังจากอึกอักเล็กน้อยก็ได้ยินเสียงเติมน้ำจากทิศทางที่หก ผ่านไป 2 นาทีขวดยังอยู่ในขั้นตอนการเติม คิวปกติมารวมตัวกันข้างหลังเรา และภาพในหัว คือความห่วงใยของลุง Petya คัดสรรเฉพาะโมเลกุล H2O ที่ดีที่สุดมาไว้ในขวดของเรา ลุง Petya ซึ่งได้รับการฝึกฝนจากชีวิตสงบจิตใจคนก้าวร้าวโดยเฉพาะและสัญญาว่าจะทำให้เสร็จโดยเร็วที่สุด เมื่อดื่มขวดเสร็จแล้วเขาก็หยิบขวดต่อไปแล้วเปิดแรงดันตามปกติซึ่งไม่ได้เปิดเผยความสามารถทั้งหมดของก๊อกน้ำใหม่ คนไม่มีความสุข... ชื่นชมเวลาด้วยสายน้ำ - 1

ทฤษฎี

มัลติเธรดคือความสามารถของแพลตฟอร์มในการสร้างหลายเธรดภายในกระบวนการเดียว การสร้างและดำเนินการเธรดนั้นง่ายกว่าการสร้างกระบวนการมาก ดังนั้นหากจำเป็นต้องใช้การดำเนินการแบบขนานหลายรายการในโปรแกรมเดียว ก็จะมีการใช้เธรดเพิ่มเติม ใน JVM โปรแกรมใดๆ ก็ตามจะรันในเธรดหลัก และส่วนที่เหลือจะถูกเรียกใช้จากเธรดหลัก ภายในกระบวนการเดียวกัน เธรดสามารถแลกเปลี่ยนข้อมูลระหว่างกันได้ เมื่อเริ่มเธรดใหม่ คุณสามารถประกาศให้เป็นเธรดผู้ใช้โดยใช้เมธอด
setDaemon(true);
เธรดดังกล่าวจะยุติโดยอัตโนมัติหากไม่มีเธรดอื่นที่ทำงานอยู่เหลืออยู่ เธรดมีลำดับความสำคัญในการทำงาน (การเลือกลำดับความสำคัญไม่ได้รับประกันว่าเธรดที่มีลำดับความสำคัญสูงสุดจะเสร็จเร็วกว่าเธรดที่มีลำดับความสำคัญต่ำกว่า)
  • MIN_PRIORITY
  • NORM_PRIORITY (ค่าเริ่มต้น)
  • MAX_PRIORITY
วิธีการพื้นฐานเมื่อทำงานกับสตรีม:
  • run()– ดำเนินการเธรด
  • start()– เริ่มกระทู้
  • getName()– ส่งคืนชื่อเธรด
  • setName()– ระบุชื่อของสตรีม
  • wait()– วิธีการสืบทอด เธรดจะรอให้เรียกวิธีการnotify()จากเธรดอื่น
  • notify()– วิธีการสืบทอด ดำเนินต่อเธรดที่หยุดไปก่อนหน้านี้
  • notifyAll()– วิธีการสืบทอด ดำเนินต่อเธรดที่หยุดไปก่อนหน้านี้
  • sleep()– หยุดการสตรีมชั่วคราวตามเวลาที่กำหนด
  • join()– รอให้เธรดเสร็จสมบูรณ์
  • interrupt()– ขัดจังหวะการทำงานของเธรด
สามารถดูวิธีการเพิ่มเติมได้ที่นี่ ถึงเวลาคิดเกี่ยวกับเธรดใหม่หากโปรแกรมของคุณมี:
  • การเข้าถึงเครือข่าย
  • การเข้าถึงระบบไฟล์
  • กุย

คลาสเธรด

เธรดใน Java แสดงเป็นคลาสThreadและคลาสสืบทอด ตัวอย่างด้านล่างนี้คือการใช้งานคลาสสตรีมอย่างง่าย
import static java.lang.System.out;

public class ExampleThread extends Thread{

    public static void main(String[] args) {
        out.println("Основной поток");
        new ExampleThread().start();
    }

    @Override
    public void run() {
        out.println("Новый поток");
    }
}
เป็นผลให้เราได้รับ
Основной поток
Новый поток
ที่นี่เราสร้างคลาสของเราและทำให้มันเป็นคลาสลูกหลานของคลาสThreadหลังจากนั้นเราจะเขียนเมธอด main() เพื่อเรียกใช้เธรดหลักและแทนที่เมธอดrun()คลาส Threadตอนนี้ เมื่อสร้างอินสแตนซ์ของคลาสของเราและดำเนินการวิธีการที่สืบทอดมาเราstart()จะเปิดตัวเธรดใหม่ซึ่งทุกสิ่งที่อธิบายไว้ในเนื้อความของวิธีการจะถูกดำเนินการ run()ฟังดูซับซ้อน แต่เมื่อดูโค้ดตัวอย่างแล้ว ทุกอย่างควรจะชัดเจน

อินเทอร์เฟซที่รันได้

ออราเคิลยังแนะนำให้ใช้อินเทอร์เฟซเพื่อเริ่มเธรดใหม่Runnableซึ่งให้ความยืดหยุ่นในการออกแบบมากกว่าการสืบทอดที่มีอยู่ในตัวอย่างก่อนหน้าเท่านั้น (หากคุณดูที่แหล่งที่มาของคลาสThreadคุณจะเห็นว่ามีการใช้อินเทอร์เฟซด้วยRunnable) ลองใช้วิธีที่แนะนำในการสร้างเธรดใหม่
import static java.lang.System.out;

public class ExampleRunnable implements Runnable {

    public static void main(String[] args) {
        out.println("Основной поток");
        new Thread(new ExampleRunnable()).start();
    }

    @Override
    public void run() {
        out.println("Новый поток");
    }
}
เป็นผลให้เราได้รับ
Основной поток
Новый поток
ตัวอย่างจะคล้ายกันมากเพราะว่า เมื่อเขียนโค้ด เราต้องใช้วิธีนามธรรมrun()ที่อธิบายไว้ในอินเทอร์เฟRunnableซ การเปิดกระทู้ใหม่จะแตกต่างออกไปเล็กน้อย เราสร้างอินสแตนซ์ของคลาสThreadโดยส่งการอ้างอิงไปยังอินสแตนซ์ของการใช้งานอินเทอร์เฟซของเราเป็นRunnableพารามิเตอร์ เป็นแนวทางนี้ที่ช่วยให้คุณสามารถสร้างเธรดใหม่โดยไม่ต้องสืบทอดคลาสThreadโดยตรง

การดำเนินงานที่ยาวนาน

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

    public static void main(String[] args) {
        // Узнаем стартовое время программы
        long startTime = System.currentTimeMillis();

        // Определяем долгосрочные операции
        for(double i = 0; i < 999999999; i++){
        }
        System.out.println("complete 1");
        for(double i = 0; i < 999999999; i++){
        }
        System.out.println("complete 2");
        for(double i = 0; i < 999999999; i++){
        }
        System.out.println("complete 3");

        //Вычисляем и выводим время выполнения программы
        long timeSpent = System.currentTimeMillis() - startTime;
        System.out.println("программа выполнялась " + timeSpent + " миллисекунд");
    }
}
เป็นผลให้เราได้รับ
complete 1
complete 2
complete 3
программа выполнялась 9885 миллисекунд
เวลาดำเนินการไม่เป็นที่ต้องการมากนักและตลอดเวลานี้เรากำลังดูหน้าจอเอาต์พุตที่ว่างเปล่าและสถานการณ์ก็คล้ายกับเรื่องราวเกี่ยวกับลุง Petya มาก แต่ตอนนี้เราซึ่งเป็นผู้พัฒนาไม่ได้ใช้ประโยชน์จากบทบาทของเขา ความสามารถทั้งหมดของอุปกรณ์ที่ทันสมัย เราจะปรับปรุง
public class ComputeClass {

    public static void main(String[] args) {
        // Узнаем стартовое время программы
        long startTime = System.currentTimeMillis();

        // Определяем долгосрочные операции
        new MyThread(1).start();
        new MyThread(2).start();
        for(double i = 0; i < 999999999; i++){
        }
        System.out.println("complete 3");

        //Вычисляем и выводим время выполнения программы
        long timeSpent = System.currentTimeMillis() - startTime;
        System.out.println("программа выполнялась " + timeSpent + " миллисекунд");
    }
}

class MyThread extends Thread{
int n;

MyThread(int n){
    this.n = n;
}

    @Override
    public void run() {
        for(double i = 0; i < 999999999; i++){
        }
        System.out.println("complete " + n);
    }
}
เป็นผลให้เราได้รับ
complete 1
complete 2
complete 3
программа выполнялась 3466 миллисекунд
เวลาทำงานลดลงอย่างมาก (ผลกระทบนี้อาจไม่เกิดขึ้นหรืออาจเพิ่มเวลาดำเนินการบนโปรเซสเซอร์ที่ไม่รองรับมัลติเธรด) เป็นที่น่าสังเกตว่าเธรดอาจไม่เป็นระเบียบ และหากนักพัฒนาต้องการความสามารถในการคาดเดาการดำเนินการ เขาจะต้องดำเนินการอย่างอิสระสำหรับกรณีเฉพาะ

กลุ่มกระทู้

เธรดใน Java สามารถรวมเป็นกลุ่มได้ โดยคลาสนี้ใช้สำหรับThreadGroup. กลุ่มสามารถมีทั้งเธรดเดี่ยวและทั้งกลุ่ม วิธีนี้จะสะดวกถ้าคุณต้องการขัดจังหวะโฟลว์ที่เกี่ยวข้อง เช่น กับเครือข่ายเมื่อการเชื่อมต่อขาดหาย คุณสามารถอ่านเพิ่มเติมเกี่ยวกับกลุ่มได้ที่นี่ ฉันหวังว่าตอนนี้หัวข้อจะชัดเจนยิ่งขึ้นสำหรับคุณ และผู้ใช้ของคุณจะพึงพอใจ
ชื่นชมเวลาด้วยสายน้ำ - 2
ความคิดเห็น
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION