Callable
接口
public interface Callable<V> {
V call() throws Exception;
}
测试类
package com.hanbin.mybatisdemo.thread;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
/**
* @author hanbin.jiang
* @version 1.0.0
* @ClassName CallableTest.java
* @createTime 2022年06月17日 19:37:00
* @Description TODO
*/
public class CallableTest implements Callable<String> {
private String string;
public CallableTest(String string) {
this.string = string;
}
@Override
public String call() throws Exception {
//任务阻塞5秒,异常向上抛出
Thread.sleep(5000);
return this.string;
}
// 异常也可以try catch解决
// @Override
// public String call(){
// //任务阻塞5秒 异常向上抛出
// try {
// Thread.sleep(5000);
// } catch (InterruptedException e) {
// e.printStackTrace();
// }
// return this.string;
// }
public static void main(String[] args) throws ExecutionException, InterruptedException {
Callable<String> callable = new CallableTest("my callable is ok!");
FutureTask<String> task = new FutureTask<String>(callable);
long beginTime = System.currentTimeMillis();
//创建线程
new Thread(task).start();
//调用get()方法阻塞主线程
String str = task.get();
long endTime = System.currentTimeMillis();
System.out.println("hello :"+ str);
System.out.println("time :"+ (endTime - beginTime)/1000);
}
}
测试输出:间隔五秒之后输出
Runnable
接口
public interface Runnable {
void run();
}
测试类
package com.hanbin.mybatisdemo.thread;
/**
* @author hanbin.jiang
* @version 1.0.0
* @ClassName RunnableTest.java
* @createTime 2022年06月17日 19:41:00
* @Description TODO
*/
public class RunnableTest implements Runnable{
private String str;
public RunnableTest(String str) {
this.str = str;
}
@Override
public void run() {
try {
//线程休眠5s,有异常产生,只能内部解决,无法向上抛
Thread.sleep(5000);
} catch (InterruptedException e) {
e.printStackTrace();
}
//5s之后输出
System.out.println("hello:" + this.str);
}
public static void main(String[] args) {
Runnable runnable = new RunnableTest("my runnable is ok");
Long beginTime = System.currentTimeMillis();
Thread thread=new Thread(()->{
runnable.run();
});
thread.start();
Long endTime = System.currentTimeMillis();
//先输出
System.out.println("time:" + (endTime-beginTime)/1000);
}
}
测试结果:
两者的区别
1、最大的区别,runnable没有返回值,而实现callable接口的任务线程能返回执行结果
2、callable接口实现类中的run方法允许异常向上抛出,可以在内部处理,try catch,但是runnable接口实现类中run方法的异常必须在内部处理,不能抛出
补充Executor框架
Executor框架是由任务,任务的执行,异步计算的结果组成
- Executor是一个接口,它是Executor框架的基础,它将任务的提交与任务的执行分离开来;
- ThreadPoolExecutor是线程池的核心实现类,用来执行被提交的任务;
- ScheduledThreadPoolExecutor是一个实现类,可以在给定的延迟后运行命令,或者定期执行命令。ScheduledThreadPoolExecutor比Timer更灵活,功能更强大;
- Future接口和实现Future接口的FutureTask类,代表异步计算的结果;
- Runnable接口和Callable接口的实现类,都可以被ThreadPoolExecutor或Scheduled-ThreadPoolExecutor执行;
框架使用示意图:
框架使用解释:
主线程首先要创建实现Runnable或者Callable接口的任务对象。工具类Executors可以把一
个Runnable对象封装为一个Callable对象(Executors.callable(Runnable task)或 Executors.callable(Runnable task,Object resule))。
然后可以把Runnable对象直接交给ExecutorService执行(ExecutorService.execute(Runnable command));或者也可以把Runnable对象或Callable对象提交给ExecutorService执行(ExecutorService.submit(Runnable task)或ExecutorService.submit(Callabletask))。
如果执行ExecutorService.submit(…),ExecutorService将返回一个实现Future接口的对象(到目前为止的JDK中,返回的是FutureTask对象)。由于FutureTask实现了Runnable,我们也可以创建FutureTask,然后直接交给ExecutorService执行。
最后,主线程可以执行FutureTask.get()方法来等待任务执行完成。主线程也可以执行 FutureTask.cancel(boolean mayInterruptIfRunning)来取消此任务的执行。