参考:
Callable 与 Runnable 对比:
相同:都是可被其它线程执行的任务。
不同:
①Callable规定的方法是call(),而Runnable规定的方法是run().
②Callable的任务执行后可返回值,而Runnable的任务是不能返回值的
③call()方法可抛出异常,而run()方法是不能抛出异常的。
④运行Callable任务可拿到一个Future对象,Future表示异步计算的结果。通过Future对象可了解任务执行情况,可取消任务的执行。
public interface Callable<V> {
V call() throws Exception;
}
public interface Runnable {
void run();
}
- 相同点
都是接口
都可以编写多线程程序
都采用Thread.start()启动线程
- 不同点
Runnable没有返回值;Callable可以返回执行结果,是个泛型,和Future、FutureTask配合可以用来获取异步执行的结果
Callable接口的call()方法允许抛出异常;Runnable的run()方法异常只能在内部消化,不能往上继续抛
注:Callalbe接口支持返回执行结果,需要调用FutureTask.get()得到,此方法会阻塞主进程的继续往下执行,如果不调用不会阻塞。
package day4;
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class Test1 {
public static void main(String[] args) {
Runnable runnable = new Runnable() {
@Override
public void run() {
}
};
Thread thread1 = new Thread(runnable, "RunnableThread");
thread1.start();
//====================================================
//1、创建Callable接口的实现类,并实现call()方法
Callable<Integer> callable = new Callable<>() {
@Override
public Integer call() throws Exception {
return new Random().nextInt(100);
}
};
//2、使用FutureTask类来包装Callable对象,
// 该FutureTask对象封装了Callable对象的call()方法的返回值
FutureTask<Integer> future = new FutureTask<>(callable);
//3、使用FutureTask对象作为Thread对象的target创建并启动线程
// (因为FutureTask实现了Runnable接口
Thread thread2 = new Thread(future, "CallableThread");
thread2.start();
try {
//4、调用FutureTask对象的get()方法来获得子线程执行结束后的返回值
//get()方法会阻塞,直到子线程执行结束才返回
Integer integer = future.get();
System.out.println("integer==============>" + integer);
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
示例一:
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CallableAndFuture {
public static void main(String[] args) {
Callable<Integer> callable = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
Thread.sleep(6000);
return new Random().nextInt();
}
};
FutureTask<Integer> future = new FutureTask<>(callable);
new Thread(future).start();
try {
Thread.sleep(1000);
System.out.println("----hello begin----");
System.out.println(future.isDone());
System.out.println(future.get());
System.out.println(future.isDone());
System.out.println("----hello end----");
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
//----hello begin----
//false
//148033037
//true
//----hello end----
示例二:
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CallableThreadTest implements Callable<Integer> {
public static void main(String[] args) throws ExecutionException, InterruptedException {
CallableThreadTest ctt = new CallableThreadTest();
FutureTask<Integer> futureTask = new FutureTask<>(ctt);
new Thread(futureTask, "有返回值的线程").start();
System.out.println("子线程的返回值" + futureTask.get());
}
@Override
public Integer call() {
int i;
for (i = 0; i < 10; i += 2) {
System.out.println(Thread.currentThread().getName() + " " + i);
}
return i;
}
}
//有返回值的线程 0
//有返回值的线程 2
//有返回值的线程 4
//有返回值的线程 6
//有返回值的线程 8
//子线程的返回值10
示例三:
多线程返回执行结果是很有用的一个特性,
因为多线程相比单线程更难、更复杂的一个重要原因就是因为多线程充满着未知性,
- 某条线程是否执行了?
- 某条线程执行了多久?
- 某条线程执行的时候我们期望的数据是否已经赋值完毕?
无法得知,我们能做的只是等待这条多线程的任务执行完毕而已。
而Callable+Future/FutureTask却可以获取多线程运行的结果,
可以在等待时间太长没获取到需要的数据的情况下取消该线程的任务,真的是非常有用。
import java.util.Random;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class CallableAndFuture2 {
public static void main(String[] args) {
Callable<Integer> callable = new Callable<Integer>() {
@Override
public Integer call() throws Exception {
Thread.sleep(6000);
return new Random().nextInt();
}
};
FutureTask<Integer> futureTask = new FutureTask<>(callable);
new Thread(futureTask).start();
try {
Thread.sleep(1000);
System.out.println("----hello begin----");
System.out.println(futureTask.isDone());
futureTask.cancel(false); //取消
if (!futureTask.isCancelled()) {
System.out.println(futureTask.get());
System.out.println(futureTask.isDone());
System.out.println("----hello end----");
} else {
System.out.println("______cancel_____");
}
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
}
}
}
//----hello begin----
//false
//______cancel_____