Callable与Runnable的关系
异同点:
- 他们都可以作为线程的实现接口
- Callable有返回值,而 Runnable没有返回值
- Callable可以抛出异常,而Runnable不能
- Callable的实现方法为 Call() ,Runnable的实现方法为Run()
这些都是我们明面上能看到的区别。
二者与Thread的关系
Thread 是我们最常用的 线程实现类,他和 Runnable 有着 很直接的关系:
Thread 实现了 Runnable 接口,是的,,这相当直接。
但我们找不出 Thread 和 Callable 的直接关系,所以我们只能间接着来。
Thread 往上推一层是 Runnable
在 Runnable 的实现类里寻找:
进来之后:
在看其构造方法:
一个小例子阐述一下这三者的关系:Callable 、FutureTask, Thread
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
import java.util.concurrent.TimeUnit;
/**
* @ClassName CallableTest
* @Description
* @Author SkySong
* @Date 2020-10-13 21:33
*/
public class CallableTest {
public static void main(String[] args) throws ExecutionException, InterruptedException {
MyThread callable = new MyThread();
FutureTask<String> futureTask = new FutureTask<>(callable);
new Thread(futureTask,"线程A").start();
new Thread(futureTask,"线程B").start();
//获得返回值
// 这个get() 方法可能会产生阻塞
// (当call()方法为耗时操作时,这里的 get 迟迟得不到返回值,就会一直等着)
// 所以我们建议把 get() 方法写到程序最后一行,或者 采用异步操作。
String s = futureTask.get();
System.out.println(s);
}
}
class MyThread implements Callable<String> {
@Override
public String call() throws Exception {
System.out.println("call()");
TimeUnit.SECONDS.sleep(1);
return "SkySong";
}
}
执行结果:
call()
SkySong
结果说明:
- 只打印了一遍 “call()”
- 说明 Callable 实现的线程类,在调用时 会有 缓存 效果。
- 再有就是 get() 方法 可能会导致阻塞,详见代码注释。
Callable创建线程
import java.util.concurrent.*;
/**
* @ClassName ThreadCallable
* @Description
* @Author SkySong
* @Date 2020-10-04 17:37
*/
public class ThreadCallable {
public static void main(String[] args) throws ExecutionException, InterruptedException {
CallableWay callableWay1 = new CallableWay();
CallableWay callableWay2 = new CallableWay();
CallableWay callableWay3 = new CallableWay();
//2.创建执行服务(类似于线程池)
ExecutorService service = Executors.newFixedThreadPool(3);
//3.提交服务
Future<String> f1 = service.submit(callableWay1);
Future<String> f2 = service.submit(callableWay2);
Future<String> f3 = service.submit(callableWay3);
//4.获取结果
System.out.println(f1.get());
System.out.println(f2.get());
System.out.println(f3.get());
//5.关闭服务
service.shutdown();
}
}
//1.实现 Callable 接口,创建线程类
class CallableWay implements Callable<String> {
@Override
public String call() throws Exception {
for (int i = 1; i <= 10; i++) {
System.out.println(Thread.currentThread().getName() + " " +i);
}
return Thread.currentThread().getName()+"结束";
}
}
简单阐述:
首先实现 Callable 接口创建线程类,,
- call()方法就是输出一下 1–10,最后返回线程的名字加 “结束” 二字。
- 接着一下创建了 3 个线程对象
- 创建服务,然后将 前面创建的三个线程对象放进去
(保留意见,这地方有点像线程池)
- 提交服务,到这儿就意味着线程要开始执行了(由服务把线程调起来)
- 等待获取结果
- 关闭服务