Yanıtlar:
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.
Ne uygulamalarındaki farklılıklar
Runnable
veCallable
. Fark sadece dönüş parametresi mevcutCallable
mu?
Temel olarak, evet. Bu sorunun cevaplarına bakın . Ve javadoc içinCallable
.
Her
Callable
şeyi yapabiliyorsa ikisine birden sahip olmanın ihtiyacı nedirRunnable
?
Çünkü Runnable
arabirim olamaz her şeyi Callable
yapar!
Runnable
Java 1.0'dan beri var, ancak Callable
yalnı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 Runnable
kullanmaktan Callable<Void>
ve döndürmekten daha özlüdür .null
call()
Runnable
geriye dönük uyumluluk nedeniyle (büyük ölçüde) var olduğunu önerirsiniz . Ancak, Callable
arayü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?
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.)
Callable
uygulamak call()
gerekirken bir yöntem Runnable
uygulamak gerekir run()
.Callable
bir değer döndürebilir, ancak bir değer döndüremez Runnable
.Callable
işaretli istisna atabilir ama bir Runnable
yapamaz.A yöntemlerle Callable
kullanı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;
}
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:
Callable<V>
örnek türün sonucunu döndürür V
, ancak bir örnek döndürmez Runnable
.Callable<V>
örnek işaretli istisnalar atabilir, ancak bir Runnable
örnekJava tasarımcıları Runnable
arayüzün yeteneklerini genişletme ihtiyacı hissettiler , ancak arayüzün kullanımını etkilemek istemediler Runnable
ve muhtemelen Callable
Java 1.5'te zaten değiştirilmiş olandan farklı bir arayüze sahip olmalarının nedeni buydu. mevcut Runnable
.
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.
Callable
interface 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
Runnable
bir oysa bir amacı bir sonuç döndürmez Callable
nesnenin bir sonuç verir.Runnable
nesne işaretli bir istisnayı Callable
alamaz, bir nesne bir istisna atayabilir .Runnable
Oysa arayüzü Java 1.0 yana yaklaşık edilmiş Callable
ancak Java 1.5 tanıtıldı.Birkaç benzerlik şunları içerir:
ExecutorService arabirimindeki yöntemler
<T> Future<T> submit(Callable<T> task);
Future<?> submit(Runnable task);
<T> Future<T> submit(Runnable task, T result);
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. Callable
Arayüz benzer Runnable
iki olan örnekleri, potansiyel olarak başka bir iş parçacığı yürütür sınıfları için tasarlanmıştır bu. A Runnable
Ancak bir sonuç dönmez ve bir kontrol istisna olamaz.
Diğer farklılıklar:
Runnable
Bir Konu oluşturmak için geçebilirsiniz . Ancak Callable
parametre olarak ileterek yeni Konu oluşturamazsınız . Callable öğesini yalnızca ExecutorService
örneklere geçirebilirsiniz .
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();
}
}
Runnable
Ateş için kullanın ve çağrıları unutun. Sonucu Callable
doğrulamak için kullanın .
Callable
aksine invokeAll yöntemine geçirilebilir Runnable
. Yöntemler invokeAny
ve invokeAll
en 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
Önemsiz farkı: yöntem adı => uygulanacak run()
için Runnable
ve call()
için Callable
.
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.
Future
veya kullanılmayan tüm istisnaları yakalayan kanca ekleyerek veya bazı çabalar gerçekleştirmeniz gerekir : docs.oracle.com/javase/6/docs/api/ java / lang /…
Thread
, Callable
arayü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 ...
+-------------------------------------+--------------------------------------------------------------------------------------------------+
| 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ı Runnable
arayüzün yeteneklerini genişletme ihtiyacı hissettiler , ancak arayüzün kullanımlarını etkilemek istemediler Runnable
ve muhtemelen Callable
Java 1.5'te zaten değiştirilmiş olandan farklı bir arayüze sahip olmalarının nedeni buydu. Runnable
Java 1.0'dan beri Java'nın bir parçası olan mevcut arayüz. kaynak
Callable ve Runnable arasındaki farklar şunlardır:
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.
Execnrame kullanırken Runnable (vs) Callable devreye girer.
ExecutorService, Executor
hem 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();
}
}
İş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;
}
...