Java'da Runnable ve Callable arabirimleri arasındaki fark


Yanıtlar:


444

Buradaki açıklamaya bakın .

Callable arabirimi Runnable'a benzer, çünkü her ikisi de örnekleri başka bir iş parçacığı tarafından potansiyel olarak yürütülen sınıflar için tasarlanmıştır. Ancak Runnable bir sonuç döndürmez ve işaretli bir istisna alamaz.


269

Ne uygulamalarındaki farklılıklar Runnableve Callable. Fark sadece dönüş parametresi mevcut Callablemu?

Temel olarak, evet. Bu sorunun cevaplarına bakın . Ve javadoc içinCallable .

Her Callableşeyi yapabiliyorsa ikisine birden sahip olmanın ihtiyacı nedir Runnable?

Çünkü Runnablearabirim olamaz her şeyi Callableyapar!

RunnableJava 1.0'dan beri var, ancak Callableyalnızca Java 1.5'te tanıtılmadı Runnable. Teorik olarak, Java ekibi Runnable.run()yöntemin imzasını değiştirmiş olabilir , ancak bu, 1.5 öncesi kodla ikili uyumluluğu bozmuş ve eski Java kodunu daha yeni JVM'lere geçirirken yeniden kodlama gerektirecektir. Bu büyük bir hayır-hayır. Java geriye dönük olarak uyumlu olmaya çalışır ... ve bu, Java'nın ticari bilgi işlem için en büyük satış noktalarından biridir.

Ve açıkça, bir görevin bir sonuç döndürmesi veya kontrol edilen bir istisna atması gerekmediği kullanım durumları vardır . Bu kullanım durumları için, kullanma yöntemi yöntemden bir kukla ( ) değeri Runnablekullanmaktan Callable<Void>ve döndürmekten daha özlüdür .nullcall()


9
Acaba bu tarihi nereden buldun? Bu çok faydalı.
örümcek adam

4
@prash - temel gerçekler eski ders kitaplarında bulunur. Özetle Java'nın ilk baskısı gibi.
Stephen C

4
(@prash - Ayrıca ... Java 1.1 döneminde Java kullanmaya başlayarak.)
Stephen C

1
@StephenC Cevabınızı doğru okursam, Runnablegeriye dönük uyumluluk nedeniyle (büyük ölçüde) var olduğunu önerirsiniz . Ancak, Callablearayüzün uygulanmasının (veya zorunlu kılınmasının) gereksiz veya çok pahalı olduğu durumlar (örneğin, içinde ScheduledFuture<?> ScheduledExecutorService.schedule(Runnable command, long delay, TimeUnit unit)) yok mu? Öyleyse, tarihin mevcut sonucu zorlamamasına rağmen dilde her iki arayüzü de korumanın bir yararı yok mu?
maksimum

1
@max - Bunu söyledim ve hala buna katılıyorum. Ancak, bu ikincil bir nedendir. Ama yine de, ben şüpheli Runnable olurdu uyumluluğu sağlamak için bir zorunluluk yoktur olmasaydı güncellenmiştir. "Ortak plakası" return null;zayıf bir argüman. (En azından bu benim kararım olurdu ... geriye dönük uyumluluğu görmezden gelebileceğiniz varsayımsal bağlamda.)
Stephen C

82
  • Bir yöntem Callableuygulamak call()gerekirken bir yöntem Runnableuygulamak gerekir run().
  • A Callablebir değer döndürebilir, ancak bir değer döndüremez Runnable.
  • Bir Callableişaretli istisna atabilir ama bir Runnableyapamaz.
  • A yöntemlerle Callablekullanılabilir, ExecutorService#invokeXXX(Collection<? extends Callable<T>> tasks)ancak kullanılamaz Runnable.

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

17
ExecutorService.submit (Çalıştırılabilir görev) de var ve çok kullanışlı
Yair Kukielka

Runnable ayrıca aşağıdaki yollarla ExecutorService ile kullanılabilir- 1) ExecutorService.execute (Runnable) 2) ExecutorService.submit (Runnable)
Azam Han

2
Ayrıca Executor.submit (Callable <T> görevi) var ama Runnable görevleri Koleksiyonu <ile invokeAll veya invokeAny olamaz? Callable <T>> görevlerini uzatır
nikli

36

Bunu, bu farklılıkları biraz daha açıklayabilecek başka bir blogda buldum :

Her iki arabirim de farklı bir yürütme iş parçacığında yürütmek isteyen sınıflar tarafından uygulansa da, iki arabirim arasında çok az fark vardır:

  • Bir Callable<V>örnek türün sonucunu döndürür V, ancak bir örnek döndürmez Runnable.
  • Bir Callable<V>örnek işaretli istisnalar atabilir, ancak bir Runnableörnek

Java tasarımcıları Runnablearayüzün yeteneklerini genişletme ihtiyacı hissettiler , ancak arayüzün kullanımını etkilemek istemediler Runnableve muhtemelen CallableJava 1.5'te zaten değiştirilmiş olandan farklı bir arayüze sahip olmalarının nedeni buydu. mevcut Runnable.


27

Birinin Runnable ve Callable'ı nerede kullanacağına bakalım.

Runnable ve Callable her ikisi de çağıran evreden farklı bir iş parçacığında çalışır. Ancak Callable bir değer döndürebilir ve Runnable döndüremez. Peki bu gerçekten nerede geçerlidir.

Runnable : Ateş ve unut göreviniz varsa Runnable kullanın. Kodunuzu bir Runnable'ın içine koyun ve run () yöntemi çağrıldığında görevinizi gerçekleştirebilirsiniz. Arama iş parçacığı gerçekten görevinizi yaparken umurumda değil.

Callable : Bir görevden değer almaya çalışıyorsanız Callable seçeneğini kullanın. Şimdi kendi başına çağrılabilir iş yapmaz. Callable'ınızın etrafına sardığınız ve değerlerinizi future.get () öğesinde alacağınız bir Geleceğe ihtiyacınız olacaktır. Burada, Gelecek iş parçacığı Callable'ın call () yönteminin yürütülmesini bekleyen sonuçlarla gelene kadar çağıran evre engellenir.

Bu nedenle, hem Runnable hem de Callable wrapped yöntemlerinin tanımlandığı bir hedef sınıfa bir arabirim düşünün. Çağıran sınıf, hangisinin Runnable ve hangisinin Callable olduğunu bilmeden arayüz yöntemlerinizi rastgele çağırır. Runnable yöntemleri, Callable yöntemi çağrılıncaya kadar eşzamansız olarak yürütülür. Burada, hedef sınıfınızdan değerler aldığınızdan, çağıran sınıfın iş parçacığı engellenir.

NOT: Hedef sınıfınızın içinde, tek bir iş parçacığı yürütücüsünde Callable ve Runnable çağrılarını gerçekleştirerek, bu mekanizmayı bir seri dağıtım sırasına benzer hale getirebilirsiniz. Arayan Runnable sarılı yöntemlerinizi çağırdığı sürece, çağıran evre engellemeden gerçekten hızlı çalışacaktır. Geleceğe Sarılmış bir Çağrılır yöntemini çağırır çağırmaz, sıradaki diğer tüm öğeler yürütülene kadar engellemesi gerekecektir. Ancak o zaman yöntem değerlerle döner. Bu bir senkronizasyon mekanizmasıdır.


14

Callableinterface call()yöntemi bildirir ve Nesne çağrısı () türü döndürüleceği için jenerik sağlamanız gerekir -

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Öte yandan run()runnable ile bir iş parçacığı oluşturduğunuzda ve üzerinde start () çağrısı yaptığınızda çağrılan yöntemi bildiren arabirimdir . Ayrıca doğrudan run () öğesini çağırabilirsiniz, ancak sadece run () yöntemini yürüten aynı iş parçacığıdır.

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();
}

Birkaç dikkate değer farkı özetlemek gerekirse

  1. Bir Runnablebir oysa bir amacı bir sonuç döndürmez Callablenesnenin bir sonuç verir.
  2. Bir Runnablenesne işaretli bir istisnayı Callablealamaz, bir nesne bir istisna atayabilir .
  3. RunnableOysa arayüzü Java 1.0 yana yaklaşık edilmiş Callableancak Java 1.5 tanıtıldı.

Birkaç benzerlik şunları içerir:

  1. Runnable veya Callable arabirimlerini uygulayan sınıf örnekleri, potansiyel olarak başka bir iş parçacığı tarafından yürütülür.
  2. Callable ve Runnable arabirimlerinin her ikisi de executorService tarafından Submit () yöntemi ile yürütülebilir.
  3. Her ikisi de işlevsel arabirimlerdir ve Java8'den beri Lambda ifadelerinde kullanılabilir.

ExecutorService arabirimindeki yöntemler

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

13

Bu arayüzlerin oracle dokümantasyonundan amacı:

Çalıştırılabilir arayüz, örnekleri a tarafından yürütülmesi amaçlanan herhangi bir sınıf tarafından uygulanmalıdır Thread. Sınıf, argüman çağrılmayan bir yöntem tanımlamalıdır run.

Callable : Bir sonuç döndüren ve bir istisna atabilecek bir görev. Uygulayıcılar çağrı adı verilen bağımsız değişken olmadan tek bir yöntem tanımlar. CallableArayüz benzer Runnableiki olan örnekleri, potansiyel olarak başka bir iş parçacığı yürütür sınıfları için tasarlanmıştır bu. A RunnableAncak bir sonuç dönmez ve bir kontrol istisna olamaz.

Diğer farklılıklar:

  1. RunnableBir Konu oluşturmak için geçebilirsiniz . Ancak Callableparametre olarak ileterek yeni Konu oluşturamazsınız . Callable öğesini yalnızca ExecutorServiceörneklere geçirebilirsiniz .

    Misal:

    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. RunnableAteş için kullanın ve çağrıları unutun. Sonucu Callabledoğrulamak için kullanın .

  3. Callableaksine invokeAll yöntemine geçirilebilir Runnable. Yöntemler invokeAnyve invokeAllen yaygın kullanılan toplu yürütme biçimlerini gerçekleştirme, bir görev koleksiyonu yürütme ve ardından en az bir veya tümünü tamamlamayı bekleme

  4. Önemsiz farkı: yöntem adı => uygulanacak run()için Runnableve call()için Callable.


11

Burada zaten belirtildiği gibi Callable nispeten yeni bir arayüz ve eşzamanlılık paketinin bir parçası olarak tanıtıldı. Callable ve Runnable, yürütücülerle birlikte kullanılabilir. Class Thread (Runnable'ın kendisini uygular) yalnızca Runnable'ı destekler.

Runnable'ı yine de uygulayıcılarla kullanabilirsiniz. Callable 'ın yürütücüye gönderebilmeniz ve hemen geri alabilmenizin avantajı Yürütme işlemi tamamlandığında güncellenecek olan gelecekteki sonuç. Aynı şey Runnable için de uygulanabilir, ancak bu durumda sonuçları kendiniz yönetmeniz gerekir. Örneğin, tüm sonuçları tutacak sonuç kuyruğu oluşturabilirsiniz. Diğer iş parçacığı bu sırada bekleyebilir ve gelen sonuçlarla başa çıkabilir.


Java dışarı bir istisna atma bir iplik örneği nedir merak ediyorum? ana iş parçacığı bu istisnayı yakalayabilecek mi? Değilse, Callable kullanmam. Alex, bu konuda bir fikrin var mı? Teşekkürler!
trilyonlar

1
Diğer herhangi bir kod gibi özel bir iş parçacığında çalışan kod istisna atabilir. Diğer iş parçacığında yakalamak için, özel bildirim mekanizması (örn. Dinleyicilere dayalı) kullanarak Futureveya kullanılmayan tüm istisnaları yakalayan kanca ekleyerek veya bazı çabalar gerçekleştirmeniz gerekir : docs.oracle.com/javase/6/docs/api/ java / lang /…
AlexR

Harika bilgi! Teşekkürler Alex! :)
trillions

1
Ben (yüz değerinde alınırsa doğru) biri çağrılabilir nesnelerle iş parçacığı havuzu modeli kullanması gerektiğini iddia çünkü bu cevabı iptal etti. Görünüşe göre bu talihsiz şey Thread, Callablearayüzün anlamlı kullanımı yapmak için uzatılamaz, böylece tek bir iş parçacığı geliştirilebilir şeyler ve geliştiricinin isteyebileceği diğer şeyler yapmak için özelleştirilebilir. Bu yorumu okuyan herkes benim yanlış olduğumu düşünüyorsa, daha iyi bilmek istiyorum ...

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 tasarımcıları Runnablearayüzün yeteneklerini genişletme ihtiyacı hissettiler , ancak arayüzün kullanımlarını etkilemek istemediler Runnableve muhtemelen CallableJava 1.5'te zaten değiştirilmiş olandan farklı bir arayüze sahip olmalarının nedeni buydu. RunnableJava 1.0'dan beri Java'nın bir parçası olan mevcut arayüz. kaynak


7

Callable ve Runnable arasındaki farklar şunlardır:

  1. Callable JDK 5.0'da tanıtıldı ancak Runnable, JDK 1.0'da tanıtıldı
  2. Callable, call () yöntemine sahiptir ancak Runnable, run () yöntemine sahiptir.
  3. Callable, değer döndüren çağrı yöntemine sahiptir ancak Runnable, herhangi bir değer döndürmeyen çalıştırma yöntemine sahiptir.
  4. çağrı yöntemi işaretli istisnayı atabilir, ancak çalıştırma yöntemi işaretli istisnayı atamaz.
  5. Görev kuyruğunu koymak için çağrılabilir send () yöntemi, ancak görev kuyruğuna koymak için Runnable use execute () yöntemini kullanın.

RuntimeException'ın değil, İstisna işaretlendiğinin vurgulanması önemlidir
BertKing

5

Callable ve Runnable her ikisi de birbirine benzer ve ipliğin uygulanmasında kullanılabilir. Runnable uygulaması durumunda run () yöntemini uygulamanız gerekir, ancak callable durumunda call () yöntemini uygulamanız gerekir , her iki yöntem de benzer şekilde çalışır, ancak callable call () yöntemi daha fazla esnekliğe sahiptir.

Arasındaki fark çalıştırılabilir ve çağrılabilir below-- olarak

1) runnable'ın run () yöntemi void döndürür , iş parçacığınızın daha fazla kullanabileceğiniz bir şey döndürmesini istiyorsanız Runnable run () yöntemiyle başka seçeneğiniz yoktur . Bir çözüm var 'Callable' sen şeklinde herhangi bir şey dönmek istiyorsanız, nesnenin o zaman yerine Runnable ait çağrılabilir kullanmalıdır . Çağrılabilir arabirimde Object döndüren 'call ()' yöntemi vardır .

Yöntem imzası - Çalıştırılabilir->

public void run(){}

Callable->

public Object call(){}

2) Runnable run () yöntemi durumunda, herhangi bir kontrol edilen istisna ortaya çıkarsa , try catch bloğu ile uğraşmanız gerekir , ancak Callable call () yöntemi durumunda, kontrol edilen istisnayı aşağıdaki gibi atabilirsiniz.

 public Object call() throws Exception {}

3) Runnable , eski java 1.0 sürümünden gelir , ancak çağrılabilir , Executer çerçeveli Java 1.5 sürümünde geldi .

Eğer aşina değilseniz yürütücüsü o zaman gereken yerine Runnable ait çağrılabilir kullanmak .

Umarım anlarsın.


2

Execnrame kullanırken Runnable (vs) Callable devreye girer.

ExecutorService, Executorhem Runnable hem de Callable görevlerini kabul eden bir alt arabirimdir.

Daha önce Çoklu İş Parçacığı Arabirim 1.0'dan itibaren elde edilebilir , ancak burada iş parçacığı görevini tamamladıktan sonra İş Parçacığı bilgilerini toplayamıyoruz. Verileri toplamak için Statik alanları kullanabiliriz.Runnable

Örnek Her öğrenci verilerini toplamak için ayrı evreler.

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() );
}

Bu sorunu çözmek için, 1.5'ten beri bir sonuç döndüren ve bir istisna atabilecekleri tanıttılar .Callable<V>

  • Tek Özet Yöntemi : Hem Callable hem de Runnable arabirimi tek bir soyut yönteme sahiptir, yani java 8'de lambda ifadelerinde kullanılabilir.

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

Bir ExecutorService uygulamasına yürütmek üzere görevleri devretmenin birkaç farklı yolu vardır .

  • execute(Runnable task):void yeni iş parçacığı oluşturur, ancak bu yöntem geçersiz olduğu için ana iş parçacığını veya arayan iş parçacığını engellemez.
  • submit(Callable<?>):Future<?>, future.get ()submit(Runnable):Future<?> kullandığınızda yeni iş parçacığını oluşturur ve ana iş parçacığını engeller .

Runnable, Executor framework ile çağrılabilir Arayüz kullanımına örnek.

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

İşlevsel programlama ile eşleşen bir tür arayüz adlandırma kuralıdır.

//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;
}

...
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.