ในบทความนี้ ผมจะพูดถึงวิธีที่เราสามารถสั่งซื้อเธรดต่างๆ เพื่อให้ทำงานตามลำดับที่เราต้องการ แน่นอนว่ามีวิธีดั้งเดิมในการรับประกันความเป็นระเบียบ แต่ฉันอยากจะแสดงให้คุณเห็นวิธีที่สวยงามที่เรียกว่า CompletableFuture ซึ่งถูกนำมาใช้ใน Java 8

1- CompletableFuture คืออะไร

CompletableFuture เป็นวิธีใหม่ในการรันเธรดที่ใช้งานง่ายอย่างที่คุณเห็นในตอนนี้ มาดูกันว่าเราจะรันเธรดด้วยสิ่งนี้ได้อย่างไร ขั้นแรก เราสร้างคลาส Runnable

public class TextDownloader implements Runnable {

    @Override
    public void run() {
        // Download text from server
        System.out.println("I am downloading the file containing text to a directory");
        try {
            Thread.sleep(2000); // for simulating download wait time
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

ใน TextDownloader class ฉันกำลังจำลองการดาวน์โหลดซึ่งต้องใช้เวลาพอสมควรจึงจะเสร็จสมบูรณ์ แน่นอนว่าเราต้องการเรียกใช้การดำเนินการดาวน์โหลดแยกกันดังนี้

CompletableFuture
        .runAsync(new TextDownloader());

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

public class TextProcessor implements Runnable {

    @Override
    public void run() {
        // Process downloaded text
        System.out.println("I am taking the text from the location and processing the text");
    }
}

และเรากำลังดำเนินการดังต่อไปนี้เพื่อให้แน่ใจว่ามีการสั่งซื้อ

CompletableFuture
        .runAsync(new TextDownloader())
        .thenRunAsync(new TextProcessor());

วิธีการ thenRunAsyncช่วยให้แน่ใจว่าเธรดที่ดำเนินการผ่าน runAsync เสร็จสมบูรณ์ จากนั้นจึงเรียกใช้สิ่งที่ได้รับ ในตัวอย่างข้างต้น เราถือว่าเธรดที่สองรู้อยู่แล้วว่า เธรด แรกวางไฟล์ที่ดาวน์โหลดไว้ในระบบไฟล์ แต่ถ้าไม่เป็นเช่นนั้นล่ะ? มาดูกันว่าซัพพลายเออร์จะจัดการอย่างไร

public class TextDownloader2 implements Supplier<String> {

    @Override
    public String get() {
        System.out.println("I am downloading the file containing text to a directory");
        try {
            Thread.sleep(2000); // for simulating download wait time
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        return "pathToDownloadedFile";
    }
}

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

public class TextProcessor2 implements Consumer<String> {

    @Override
    public void accept(String s) {
        // Process downloaded text
        System.out.println("I am taking the text from the location and processing the text");
        System.out.println("Path: " + s);
    }
}

และเราจะใช้มันร่วมกันได้อย่างไร

CompletableFuture
        .supplyAsync(new TextDownloader2())
        .thenAccept(new TextProcessor2());

คุณยังสามารถระบุตรรกะของคุณได้โดยตรงภายใน thenAccept ดังนี้

CompletableFuture
        .supplyAsync(new TextDownloader2())
        .thenAccept(path -> {
            // some logic
        });

มีวิธีการต่างๆ ในคลาส CompletableFuture ที่คุณสามารถใช้ได้ เช่น thenAcceptAsync หรือ thenApplyแต่ฉันไม่ต้องการทำให้บทความยาวขึ้นในตอนนี้

ในบทช่วยสอนนี้ ฉันพูดคุยเกี่ยวกับการเรียงลำดับการประมวลผลเธรด ฉันหวังว่าคุณจะสนุกกับมัน.