Відповіді:
Дивіться пояснення тут .
Інтерфейс Callable схожий на Runnable, оскільки обидва розроблені для класів, екземпляри яких потенційно виконуються іншим потоком. Однак Runnable не повертає результату і не може кинути перевірений виняток.
Які відмінності у застосуванні
Runnable
таCallable
. Чи присутня різниця лише з параметром поверненняCallable
?
В основному, так. Дивіться відповіді на це питання . І javadoc дляCallable
.
Яка потреба мати обох, якщо
Callable
можна робити все, щоRunnable
робить?
Тому що Runnable
інтерфейс не може робити все, що Callable
робить!
Runnable
існує вже з Java 1.0, але він Callable
був введений лише в Java 1.5 ... для обробки випадків використання, які Runnable
не підтримують. Теоретично команда Java могла змінити підпис Runnable.run()
методу, але це порушило б бінарну сумісність з кодом до 1,5, вимагаючи перекодування під час перенесення старого коду Java на новіші JVM. Це ВЕЛИКІ НІ-НІ. Java прагне бути зворотною сумісністю ... і це було одним з найбільших продажів Java для бізнес-обчислень.
І, очевидно, є випадки використання, коли завдання не потрібно повертати результат або кидати перевірений виняток. Для таких випадків використання використання Runnable
є більш стислим, ніж використання Callable<Void>
та повернення null
значення call()
методу фіктивного ( ) .
Runnable
існує (значною мірою) з причин відсталої сумісності. Але хіба не буває ситуацій, коли впроваджувати (або вимагати) Callable
інтерфейс (наприклад, в ScheduledFuture<?> ScheduledExecutorService.schedule(Runnable command, long delay, TimeUnit unit)
) це зайве або занадто дорого ? Тож чи не є користю у підтримці обох інтерфейсів у мові, навіть історія не змусила поточного результату?
Runnable
це було б змінено, якби не було необхідності збереження сумісності. "Котельня" return null;
- слабкий аргумент. (Принаймні, це було б моє рішення ... в гіпотетичному контексті, коли можна ігнорувати зворотну сумісність.)
Callable
Необхідно реалізувати call()
метод в той час як Runnable
необхідно реалізувати run()
метод.Callable
може повернути значення, але Runnable
не може.Callable
може кинути перевірений виняток, але Runnable
не може.A Callable
може використовуватися з ExecutorService#invokeXXX(Collection<? extends Callable<T>> tasks)
методами, але Runnable
не може бути.
public interface Runnable {
void run();
}
public interface Callable<V> {
V call() throws Exception;
}
Я знайшов це в іншому блозі, який може трохи більше пояснити ці відмінності :
Хоча обидва інтерфейси реалізовані класами, які бажають виконати в іншому потоці виконання, але між двома інтерфейсами є кілька відмінностей, які:
Callable<V>
Примірник повертає результат типу V
, в той час як Runnable
екземпляр не робить.Callable<V>
Примірник може кинути перевірені виключення, в той час як Runnable
екземпляр не можеДизайнери Java відчули потребу в розширенні можливостей Runnable
інтерфейсу, але вони не хотіли впливати на використання Runnable
інтерфейсу, і, ймовірно, це було причиною того, що вони почали мати окремий інтерфейс, названий Callable
в Java 1.5, ніж змінити вже існуючі Runnable
.
Давайте подивимось, де можна використовувати Runnable та Callable.
Обидва, які можна виконувати та дзвонити, працюють на іншій нитці, ніж виклична нитка. Але Callable може повернути значення, а Runnable не може. Тож де це насправді стосується.
Виконання : Якщо у вас є завдання пожежі та забуття, тоді використовуйте Runnable. Покладіть свій код всередину Runnable, і коли викликається метод run (), ви можете виконати своє завдання. Нитка виклику насправді не хвилює, коли ви виконуєте завдання.
Callable : Якщо ви намагаєтеся отримати значення із завдання, використовуйте Callable. Тепер зателефонований самостійно не зробить роботу. Вам знадобиться майбутнє, яке ви обернете навколо Callable і отримаєте свої цінності на future.get (). Тут потік виклику буде заблокований, поки Майбутнє не повернеться з результатами, які в свою чергу чекають на виконання методу call () Callable.
Тож подумайте про інтерфейс до цільового класу, де визначені методи Runnable і Callable. Клас виклику випадковим чином зателефонує у ваш метод інтерфейсу, не знаючи, що таке Runnable, а який Callable. Методи Runnable виконуватимуться асинхронно, поки не буде викликаний метод Callable. Тут потік класу виклику блокується, оскільки ви отримуєте значення з цільового класу.
ПРИМІТКА: Всередині вашого цільового класу ви можете здійснювати дзвінки на Callable та Runnable за допомогою одного виконавця потоку, що робить цей механізм подібним до черги чергової відправки. Отже, поки абонент зателефонує вашим обернутим методам Runnable, потік виклику буде виконуватись дуже швидко без блокування. Як тільки він викликає Callable, загорнутий у метод Future, йому доведеться блокувати, поки не будуть виконані всі інші елементи в черзі. Тільки тоді метод повернеться зі значеннями. Це механізм синхронізації.
Callable
інтерфейс оголошує call()
метод і вам потрібно надати загальну інформацію, оскільки тип Object call () повинен повертатися -
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()
метод, який викликається, коли ви створюєте Thread із запуском та викликом 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();
}
Підсумовуючи декілька помітних відмінностей
Runnable
Об'єкт не повертає результат , тоді як Callable
об'єкт повертає результат.Runnable
Об'єкт не може кинути перевіряється виключення Тоді як Callable
об'єкт може викликати виключення.Runnable
Інтерфейс був приблизно з Java 1.0 , тоді як Callable
був введений тільки в Java 1.5.Небагато подібності включає
Методи в інтерфейсі ExecutorService є
<T> Future<T> submit(Callable<T> task);
Future<?> submit(Runnable task);
<T> Future<T> submit(Runnable task, T result);
Призначення цих інтерфейсів із документації на oracle:
Інтерфейс для запуску повинен бути реалізований будь-яким класом, екземпляри якого призначені для виконання Thread
. Клас повинен визначати метод без викликів аргументів run
.
Викликається : завдання, яке повертає результат і може кинути виняток. Виконавці визначають єдиний метод без аргументів, званих call. Callable
Інтерфейс аналогічний Runnable
, в тому , що обидва вони призначені для класів, екземпляри потенційно виконується в іншому потоці. Але Runnable
, однак, не повертає результат і не може кинути перевірений виняток.
Інші відмінності:
Ви можете перейти 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();
}
}
Використовуйте Runnable
для пожежі та забудьте дзвінки. Використовуйте Callable
для перевірки результату.
Callable
можна передати методу invokeAll на відміну від Runnable
. Методи invokeAny
та invokeAll
виконайте найпоширеніші форми масового виконання, виконуючи колекцію завдань, а потім чекайте щонайменше одного або всіх, щоб виконати
Тривіальна різниця: ім'я методу, яке потрібно реалізувати => run()
для Runnable
і call()
для Callable
.
Як вже було сказано тут, Callable є відносно новим інтерфейсом, і він був представлений у складі пакету одночасності. Як виконавці, так і виконавці можуть використовуватися з виконавцями. Thread Class (що реалізує сам Runnable) підтримує лише Runnable.
Ви все ще можете використовувати Runnable разом із виконавцями. Перевага Callable в тому, що ви можете надіслати його виконавцю та негайно отримати майбутній результат, який буде оновлений після завершення виконання. Те саме може бути реалізовано і з Runnable, але в цьому випадку вам доведеться керувати результатами самостійно. Наприклад, ви можете створити чергу з результатами, яка буде містити всі результати. Інший потік може зачекати на цій черзі та вирішити результати, які надійдуть.
Future
або додаючи гачок, що фіксує всі неперевірені винятки: docs.oracle.com/javase/6/docs/api/ java / lang /…
Thread
на змістовне використання Callable
інтерфейсу, щоб один потік можна було налаштувати для того, щоб робити речі, що дзвонять, та інші речі, які розробник може захотіти. Якщо хтось, хто читає цей коментар, думає, що я помиляюся, я хотів би знати це краще ...
+-------------------------------------+--------------------------------------------------------------------------------------------------+
| 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. джерело
Різниця між дзвінкими, які дзвонять
Абодва, що дзвоняться та виконуються , схожі між собою та можуть використовуватись у впровадженні потоку. У разі реалізації Runnable ви повинні реалізувати метод run (), але у випадку виклику вам потрібно застосувати метод call () , обидва способи працюють аналогічно, але метод call () має більшу гнучкість. Між ними є деякі відмінності.
Різниця між Runnable і викликається , як below--
1) Run () метод працездатних повертає недійсних , кошти , якщо ви хочете , щоб ваш зворотний потік то , що ви можете використовувати в подальшому , то у вас немає іншого вибору , з Runnable Run () метод. Існує рішення "Callable". Якщо ви хочете повернути будь-яку річ у формі об'єкта, вам слід використовувати Callable замість Runnable . Інтерфейс, що викликається, має метод "call ()", який повертає "Об'єкт" .
Підпис методу - Runnable->
public void run(){}
Дзвінки->
public Object call(){}
2) У разі методу Runnable run (), якщо виникає будь-який перевірений виняток, вам потрібно обробляти блок "try catch" , але у випадку методу Callable call () ви можете кинути перевірений виняток, як показано нижче
public Object call() throws Exception {}
3) Runnable походить від застарілої версії Java 1.0 , але дзвони прийшли у версії Java 1.5 із Frameworkter .
Якщо ви знайомі з виконавцями, вам слід використовувати Callable замість Runnable .
Сподіваюся, ви зрозуміли.
Виконувана (проти) Callable вступає в дію, коли ми використовуємо Executer Framework.
ExecutorService - це підрозділ інтерфейсу Executor
, який приймає завдання як Runnable, так і Callable.
Раніше Multi-Threading можна досягти за допомогою інтерфейсу з 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>
Єдиний абстрактний метод : І Callable, і Runnable інтерфейс мають єдиний абстрактний метод, це означає, що вони можуть бути використані в лямбда-виразах в 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 () .Приклад використання інтерфейсів Runnable, Callable з програмою Executor.
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();
}
}
Це свого роду інтерфейс іменування конвенцій, який відповідає функціональному програмуванню
//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;
}
...