ความแตกต่างระหว่างอินเตอร์เฟส Runnable และ Callable ใน Java


492

อะไรคือความแตกต่างระหว่างการใช้RunnableและCallableอินเตอร์เฟสเมื่อออกแบบเธรดที่เกิดขึ้นพร้อมกันใน Java ทำไมคุณถึงเลือกอันใดอันหนึ่ง?


2
สำหรับการสนทนาเพิ่มเติมหลังจากอ่านหน้านี้แล้วจะ
barfuin

คำตอบ:


444

ดูคำอธิบายที่นี่

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


269

สิ่งที่แตกต่างในการใช้งานของและRunnable Callableมีความแตกต่างเฉพาะกับพารามิเตอร์การส่งคืนปัจจุบันCallableหรือไม่

โดยทั่วไปแล้วใช่ ดูคำตอบของคำถามนี้ และJavadoc Callableสำหรับ

ความจำเป็นของการมีทั้งถ้าเป็นสิ่งที่Callableสามารถทำได้ทุกที่Runnableที่ไม่?

เนื่องจากRunnableอินเทอร์เฟซไม่สามารถทำทุกอย่างที่Callableทำ!

Runnableมีมาตั้งแต่ Java 1.0 แต่Callableถูกนำมาใช้ใน Java 1.5 ... เพื่อจัดการกรณีใช้งานที่Runnableไม่รองรับ ในทางทฤษฎีทีม Java สามารถเปลี่ยนลายเซ็นของRunnable.run()วิธีการได้ แต่สิ่งนี้จะทำให้ความเข้ากันได้ของไบนารีแบบหักกับโค้ด pre-1.5 ซึ่งต้องการการเข้ารหัสเมื่อทำการย้ายรหัส Java เก่าไปเป็น JVM ที่ใหม่กว่า นั่นคือไม่มีใหญ่ Java มุ่งมั่นที่จะใช้งานร่วมกันได้ย้อนหลัง ... และนั่นเป็นหนึ่งในจุดขายที่ใหญ่ที่สุดของ Java สำหรับการประมวลผลทางธุรกิจ

และเห็นได้ชัดว่ามีกรณีการใช้งานที่งานไม่จำเป็นต้องส่งคืนผลหรือโยนข้อยกเว้นที่ตรวจสอบ สำหรับกรณีการใช้งานเหล่านั้นการใช้Runnableจะกระชับกว่าการใช้Callable<Void>และส่งกลับค่าดัมมี่ ( null) จากcall()เมธอด


9
ฉันสงสัยว่าคุณได้รับประวัตินี้มาจากไหน มันมีประโยชน์มาก
เดอร์แมน

4
@prash - ข้อเท็จจริงพื้นฐานจะพบได้ในหนังสือเรียนเก่า เหมือนจาวารุ่นแรกในแบบสั้น
สตีเฟ่นซี

4
(@prash - นอกจากนี้ ... โดยเริ่มใช้ Java ในยุค Java 1.1)
Stephen C

1
@StephenC หากฉันอ่านคำตอบของคุณอย่างถูกต้องคุณกำลังแนะนำว่าRunnableมีอยู่ (ส่วนใหญ่) ด้วยเหตุผลด้านความเข้ากันได้แบบย้อนหลัง แต่ไม่มีสถานการณ์ที่ไม่จำเป็นหรือแพงเกินกว่าที่จะใช้งานCallableอินเทอร์เฟซ ( หรือจำเป็น) (เช่นในScheduledFuture<?> ScheduledExecutorService.schedule(Runnable command, long delay, TimeUnit unit)) ดังนั้นจะไม่มีประโยชน์ในการรักษาทั้งสองอินเทอร์เฟซในภาษาแม้ประวัติศาสตร์ไม่ได้บังคับผลลัพธ์ปัจจุบัน
สูงสุด

1
@max - ฉันพูดอย่างนั้นแล้วและฉันก็ยังเห็นด้วย อย่างไรก็ตามนั่นเป็นเหตุผลรอง แต่ถึงกระนั้นฉันสงสัยว่าRunnable จะได้รับการแก้ไขหากไม่จำเป็นต้องรักษาความเข้ากันได้ "สำเร็จรูป" ของreturn null;เป็นอาร์กิวเมนต์ที่อ่อนแอ (อย่างน้อยนั่นก็เป็นการตัดสินใจของฉัน ... ในบริบทสมมุติที่คุณสามารถเพิกเฉยความเข้ากันได้ย้อนหลัง)
Stephen C

82
  • Callableความต้องการที่จะใช้call()วิธีการในขณะที่Runnableความต้องการที่จะใช้run()วิธีการ
  • A Callableสามารถคืนค่าได้ แต่Runnableไม่สามารถ
  • A Callableสามารถโยนข้อยกเว้นที่ตรวจสอบแล้ว แต่Runnableไม่สามารถ
  • Callableสามารถใช้ร่วมกับExecutorService#invokeXXX(Collection<? extends Callable<T>> tasks)วิธีการ แต่Runnableไม่สามารถ

    public interface Runnable {
        void run();
    }
    
    public interface Callable<V> {
        V call() throws Exception;
    }
    

17
ExecutorService.submit (งาน Runnable) ยังมีอยู่และมีประโยชน์มาก
Yair Kukielka

Runnable ยังสามารถใช้กับ ExecutorService ได้โดยทำตามวิธี - 1) ExecutorService.execute (Runnable) 2) ExecutorService.submit (Runnable)
Azam Khan

2
นอกจากนี้ยังมี Executor.submit (งาน Callable <T>) แต่คุณไม่สามารถเรียกใช้ทั้งหมดหรือ invokeAny ที่มีการรวบรวมงาน Runnable Collection ได้ <? ขยายงาน Callable <T>>
nikli

36

ฉันพบสิ่งนี้ในบล็อกอื่นที่สามารถอธิบายความแตกต่างเหล่านี้ได้มากขึ้น:

แม้ว่าอินเทอร์เฟซทั้งสองจะถูกนำมาใช้โดยคลาสที่ต้องการดำเนินการในเธรดการดำเนินการที่แตกต่างกัน แต่มีความแตกต่างเล็กน้อยระหว่างสองอินเตอร์เฟสซึ่ง ได้แก่ :

  • Callable<V>เช่นผลตอบแทนที่เป็นผลมาจากชนิดVในขณะที่Runnableอินสแตนซ์ไม่ได้
  • Callable<V>เช่นอาจจะโยนข้อยกเว้นการตรวจสอบในขณะที่Runnableตัวอย่างเช่นไม่สามารถ

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


27

ให้เราดูที่หนึ่งจะใช้ Runnable และ Callable

Runnable และ Callable ทั้งคู่ทำงานในเธรดที่แตกต่างจากเธรดการโทร แต่ Callable สามารถส่งคืนค่าได้และ Runnable ไม่สามารถทำได้ ดังนั้นสิ่งนี้นำไปใช้ที่ไหน

Runnable : ถ้าคุณมีไฟและลืมงานให้ใช้ Runnable วางรหัสของคุณไว้ใน Runnable และเมื่อเรียกใช้เมธอด run () คุณสามารถทำงานของคุณได้ เธรดการโทรไม่สนใจจริงๆเมื่อคุณทำงานของคุณ

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

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

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


14

Callableอินเตอร์เฟซประกาศcall()วิธีการและคุณต้องให้ข้อมูลทั่วไปตามประเภทของการโทร Object () ควรกลับมา -

public interface Callable<V> {
    /**
     * Computes a result, or throws an exception if unable to do so.
     *
     * @return computed result
     * @throws Exception if unable to compute a result
     */
    V call() throws Exception;
}

Runnableในทางกลับกันคืออินเทอร์เฟซที่ประกาศrun()วิธีการที่เรียกว่าเมื่อคุณสร้างเธรดที่มี runnable และ call start () บน นอกจากนี้คุณยังสามารถเรียกใช้ run () ได้โดยตรง แต่นั่นก็เป็นการเรียกใช้เมธอด run () เป็นเธรดเดียวกัน

public interface Runnable {
    /**
     * When an object implementing interface <code>Runnable</code> is used 
     * to create a thread, starting the thread causes the object's 
     * <code>run</code> method to be called in that separately executing 
     * thread. 
     * <p>
     * The general contract of the method <code>run</code> is that it may 
     * take any action whatsoever.
     *
     * @see     java.lang.Thread#run()
     */
    public abstract void run();
}

เพื่อสรุปความแตกต่างที่น่าสังเกตคือ

  1. Runnableวัตถุไม่กลับส่งผลให้ในขณะที่Callableวัตถุผลตอบแทน
  2. Runnableวัตถุไม่สามารถโยนข้อยกเว้นการตรวจสอบ wheras Callableวัตถุสามารถโยนข้อยกเว้น
  3. Runnableอินเตอร์เฟซที่ได้รับรอบตั้งแต่ Java 1.0 ในขณะที่Callableได้รับการแนะนำเฉพาะใน Java 1.5

มีความคล้ายคลึงกันน้อยมาก

  1. อินสแตนซ์ของคลาสที่ใช้อินเตอร์เฟซ Runnable หรือ Callable อาจถูกดำเนินการโดยเธรดอื่น
  2. อินสแตนซ์ของอินเทอร์เฟซทั้ง Callable และ Runnable สามารถดำเนินการได้โดย ExecutorService ผ่านทาง submit ()
  3. ทั้งสองเป็นอินเตอร์เฟสการทำงานและสามารถใช้ในนิพจน์แลมบ์ดาตั้งแต่ Java8

วิธีการในส่วนต่อประสาน ExecutorService คือ

<T> Future<T> submit(Callable<T> task);
Future<?> submit(Runnable task);
<T> Future<T> submit(Runnable task, T result);

13

วัตถุประสงค์ของอินเทอร์เฟซเหล่านี้จากเอกสารของ oracle:

RunnableThreadอินเตอร์เฟซที่ควรจะดำเนินการโดยชั้นใดมีกรณีที่มีความตั้งใจที่จะดำเนินการโดย runชั้นจะต้องกำหนดวิธีการของการขัดแย้งใดที่เรียกว่า

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

ความแตกต่างอื่น ๆ :

  1. คุณสามารถส่งผ่านRunnableเพื่อสร้างกระทู้ แต่คุณไม่สามารถสร้างเธรดใหม่ด้วยการส่งผ่านCallableพารามิเตอร์ คุณสามารถส่งผ่าน Callable ไปยังExecutorServiceอินสแตนซ์เท่านั้น

    ตัวอย่าง:

    public class HelloRunnable implements Runnable {
    
        public void run() {
            System.out.println("Hello from a thread!");
        }   
    
        public static void main(String args[]) {
            (new Thread(new HelloRunnable())).start();
        }
    
    }
  2. ใช้Runnableสำหรับยิงและลืมสาย ใช้Callableเพื่อตรวจสอบผลลัพธ์

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

  4. ความแตกต่างเล็กน้อย: ชื่อวิธีที่จะดำเนินการ => run()สำหรับRunnableและสำหรับcall()Callable


11

ตามที่ได้กล่าวมาแล้วที่นี่ Callable เป็นอินเทอร์เฟซที่ค่อนข้างใหม่และถูกนำมาใช้เป็นส่วนหนึ่งของแพ็คเกจการทำงานพร้อมกัน ทั้ง Callable และ Runnable สามารถใช้กับ executors ได้ Class Thread (ที่ใช้ Runnable เอง) รองรับ Runnable เท่านั้น

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


ฉันสงสัยว่าเป็นตัวอย่างในหัวข้อการขว้างปาข้อยกเว้นใน java คืออะไร? เธรดหลักจะสามารถจับข้อยกเว้นนั้นได้หรือไม่ ถ้าไม่ฉันจะไม่ใช้ Callable อเล็กซ์คุณมีความเข้าใจด้านนี้บ้างไหม? ขอบคุณ!
ล้านล้าน

1
รหัสที่ทำงานในเธรดที่กำหนดเองเป็นรหัสอื่นใด ๆ สามารถส่งข้อยกเว้น ในการจับมันในเธรดอื่นคุณต้องใช้ความพยายามอย่างใดอย่างหนึ่งโดยใช้กลไกการแจ้งเตือนที่กำหนดเอง (เช่นอิงจากผู้ฟัง) หรือโดยการใช้Futureหรือโดยการเพิ่มเบ็ดที่จับข้อยกเว้นที่ไม่ต้องการทั้งหมด: docs.oracle.com/javase/6/docs/api/ java / lang / …
AlexR

ข้อมูลยอดเยี่ยม! ขอบคุณอเล็กซ์! :)
ล้านล้าน

1
ฉัน upvote คำตอบนี้เพราะมันยืนยัน (อย่างถูกต้องถ้าถ่ายที่ใบหน้า) เราต้องใช้โมเดลเธรดพูลกับวัตถุที่เรียกได้ สิ่งที่โชคร้ายเกี่ยวกับเรื่องนี้คือไม่สามารถขยายThreadการใช้Callableอินเทอร์เฟซที่มีความหมายเพื่อให้สามารถปรับแต่งเธรดเดี่ยวเพื่อทำสิ่งที่เรียกได้และสิ่งอื่น ๆ ที่นักพัฒนาอาจต้องการ หากใครที่อ่านความคิดเห็นนี้คิดว่าฉันผิดฉันอยากรู้ดีกว่า ...

8
+-------------------------------------+--------------------------------------------------------------------------------------------------+
|              Runnable               |                                           Callable<T>                                            |
+-------------------------------------+--------------------------------------------------------------------------------------------------+
| Introduced in Java 1.0 of java.lang | Introduced in Java 1.5 of java.util.concurrent library                                           |
| Runnable cannot be parametrized     | Callable is a parametrized type whose type parameter indicates the return type of its run method |
| Runnable has run() method           | Callable has call() method                                                                       |
| Runnable.run() returns void         | Callable.call() returns a value of Type T                                                        |
| Can not throw Checked Exceptions    | Can throw Checked Exceptions                                                                     |
+-------------------------------------+--------------------------------------------------------------------------------------------------+

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


7

ความแตกต่างระหว่าง Callable และ Runnable มีดังต่อไปนี้:

  1. Callable ได้รับการแนะนำใน JDK 5.0 แต่มีการแนะนำ Runnable ใน JDK 1.0
  2. Callable มีเมธอด call () แต่ Runnable มีเมธอด run ()
  3. Callable มีเมธอด call ซึ่งส่งคืนค่า แต่ Runnable มีเมธอด run ซึ่งไม่ส่งคืนค่าใด ๆ
  4. วิธีการโทรสามารถโยนข้อยกเว้นที่ตรวจสอบแล้ว แต่วิธีการเรียกใช้ไม่สามารถโยนข้อยกเว้นที่ตรวจสอบได้
  5. ใช้ callable () วิธีการที่จะวางในคิวงาน แต่ใช้ Runnable execute () วิธีการที่จะวางในคิวงาน

สิ่งสำคัญคือต้องเน้นว่าการตรวจสอบข้อยกเว้นไม่ใช่ RuntimeException
BertKing

5

Callable และRunnableทั้งสองมีความคล้ายคลึงกันและสามารถใช้ในการใช้ด้าย ในกรณีที่ใช้งานRunnableคุณต้องใช้วิธีrun ()แต่ในกรณีที่ callable คุณจะต้องใช้วิธีการcall ()ทั้งสองวิธีจะทำงานในลักษณะที่คล้ายกัน แต่วิธี callable ()มีความยืดหยุ่นมากขึ้น

ความแตกต่างระหว่างRunnableและcallableดังนี้ -

1) เมธอดrun ()ของrunnableส่งคืนโมฆะหมายความว่าถ้าคุณต้องการให้เธรดของคุณส่งคืนบางสิ่งที่คุณสามารถใช้เพิ่มเติมได้จากนั้นคุณไม่มีทางเลือกด้วยเมธอดRunnable run () มีการแก้ปัญหาคือ'Callable'ถ้าคุณต้องการที่จะกลับสิ่งใด ๆ ในรูปแบบของวัตถุแล้วคุณควรใช้ Callable แทน Runnable อินเตอร์เฟซ Callable มีวิธีการ'โทร ()' ซึ่งผลตอบแทนวัตถุ

ลายเซ็นเมธอด - Runnable->

public void run(){}

Callable->

public Object call(){}

2) ในกรณีที่Runnable run ()วิธีการถ้ามีการตรวจสอบข้อยกเว้นเกิดขึ้นคุณจะต้องจัดการกับลอง catch catch blockแต่ในกรณีที่Callable call ()วิธีการคุณสามารถโยนยกเว้นการตรวจสอบดังต่อไปนี้

 public Object call() throws Exception {}

3) Runnableมาจากรุ่นjava 1.0รุ่นเก่า แต่callableมาในรุ่นJava 1.5 ที่มีเฟรมเวิร์กExecuter

หากคุณมีความคุ้นเคยกับExecutersแล้วคุณควรใช้ Callable แทน Runnable

หวังว่าคุณจะเข้าใจ.


2

Runnable (vs) Callableเข้ามาในจุดเมื่อเราใช้ Executer framework

ExecutorService เป็นส่วนย่อยของExecutorซึ่งยอมรับทั้งงาน Runnable และ Callable

Multi-Threading ก่อนหน้านี้สามารถทำได้โดยใช้ Interface ตั้งแต่ 1.0แต่ที่นี่ปัญหาคือหลังจากทำงานเธรดเสร็จแล้วเราไม่สามารถรวบรวมข้อมูลเธรดได้ เพื่อรวบรวมข้อมูลเราอาจใช้ฟิลด์คงที่Runnable

ตัวอย่างคั่นหัวข้อเพื่อรวบรวมข้อมูลนักเรียนแต่ละคน

static HashMap<String, List> multiTasksData = new HashMap();
public static void main(String[] args) {
    Thread t1 = new Thread( new RunnableImpl(1), "T1" );
    Thread t2 = new Thread( new RunnableImpl(2), "T2" );
    Thread t3 = new Thread( new RunnableImpl(3), "T3" );

    multiTasksData.put("T1", new ArrayList() ); // later get the value and update it.
    multiTasksData.put("T2", new ArrayList() );
    multiTasksData.put("T3", new ArrayList() );
}

เพื่อแก้ไขปัญหานี้พวกเขาได้แนะนำตั้งแต่ 1.5ซึ่งส่งคืนผลลัพธ์และอาจมีข้อยกเว้นCallable<V>

  • Single Abstract Method : ทั้ง Callable และ Runnable interface มีวิธีนามธรรมเดียวซึ่งหมายความว่าสามารถใช้ในการแสดงออกแลมบ์ดาใน java 8

    public interface Runnable {
    public void run();
    }
    
    public interface Callable<Object> {
        public Object call() throws Exception;
    }

มีวิธีการที่แตกต่างกันไม่กี่ที่จะมอบหมายงานสำหรับการดำเนินการกับผู้มีExecutorService

  • execute(Runnable task):void สร้างเธรดใหม่ แต่ไม่บล็อกเธรดหลักหรือเธรดผู้เรียกเนื่องจากเมธอดนี้ส่งคืนโมฆะ
  • submit(Callable<?>):Future<?>, submit(Runnable):Future<?>ลังหัวข้อใหม่และบล็อกหัวข้อหลักเมื่อคุณกำลังใช้future.get ()

ตัวอย่างของการใช้อินเทอร์เฟซเรียกใช้ได้เรียกใช้ได้ด้วยกรอบงานของผู้บริหาร

class CallableTask implements Callable<Integer> {
    private int num = 0;
    public CallableTask(int num) {
        this.num = num;
    }
    @Override
    public Integer call() throws Exception {
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName + " : Started Task...");

        for (int i = 0; i < 5; i++) {
            System.out.println(i + " : " + threadName + " : " + num);
            num = num + i;
            MainThread_Wait_TillWorkerThreadsComplete.sleep(1);
        }
        System.out.println(threadName + " : Completed Task. Final Value : "+ num);

        return num;
    }
}
class RunnableTask implements Runnable {
    private int num = 0;
    public RunnableTask(int num) {
        this.num = num;
    }
    @Override
    public void run() {
        String threadName = Thread.currentThread().getName();
        System.out.println(threadName + " : Started Task...");

        for (int i = 0; i < 5; i++) {
            System.out.println(i + " : " + threadName + " : " + num);
            num = num + i;
            MainThread_Wait_TillWorkerThreadsComplete.sleep(1);
        }
        System.out.println(threadName + " : Completed Task. Final Value : "+ num);
    }
}
public class MainThread_Wait_TillWorkerThreadsComplete {
    public static void main(String[] args) throws InterruptedException, ExecutionException {
        System.out.println("Main Thread start...");
        Instant start = java.time.Instant.now();

        runnableThreads();
        callableThreads();

        Instant end = java.time.Instant.now();
        Duration between = java.time.Duration.between(start, end);
        System.out.format("Time taken : %02d:%02d.%04d \n", between.toMinutes(), between.getSeconds(), between.toMillis()); 

        System.out.println("Main Thread completed...");
    }
    public static void runnableThreads() throws InterruptedException, ExecutionException {
        ExecutorService executor = Executors.newFixedThreadPool(4);
        Future<?> f1 = executor.submit( new RunnableTask(5) );
        Future<?> f2 = executor.submit( new RunnableTask(2) );
        Future<?> f3 = executor.submit( new RunnableTask(1) );

        // Waits until pool-thread complete, return null upon successful completion.
        System.out.println("F1 : "+ f1.get());
        System.out.println("F2 : "+ f2.get());
        System.out.println("F3 : "+ f3.get());

        executor.shutdown();
    }
    public static void callableThreads() throws InterruptedException, ExecutionException {
        ExecutorService executor = Executors.newFixedThreadPool(4);
        Future<Integer> f1 = executor.submit( new CallableTask(5) );
        Future<Integer> f2 = executor.submit( new CallableTask(2) );
        Future<Integer> f3 = executor.submit( new CallableTask(1) );

        // Waits until pool-thread complete, returns the result.
        System.out.println("F1 : "+ f1.get());
        System.out.println("F2 : "+ f2.get());
        System.out.println("F3 : "+ f3.get());

        executor.shutdown();
    }
}

0

มันเป็นประเภทของการตั้งชื่ออินเตอร์เฟซที่ตรงกับการเขียนโปรแกรมการทำงาน

//Runnable
interface Runnable {
    void run();
}

//Action - throws exception
interface Action {
    void run() throws Exception;
}

//Consumer - consumes a value/values, throws exception
interface Consumer1<T> {
    void accept(T t) throws Exception;
}

//Callable - return result, throws exception
interface Callable<R> {
    R call() throws Exception;
}

//Supplier - returns result, throws exception
interface Supplier<R> {
    R get() throws Exception;
}

//Predicate - consumes a value/values, returns true or false, throws exception
interface Predicate1<T> {
    boolean test(T t) throws Exception;
}

//Function - consumes a value/values, returns result, throws exception
public interface Function1<T, R> {
    R apply(T t) throws Throwable;
}

...
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.