Runnable
Runnable 接口非常简单, 就定义了一个办法 run(), 实现 Runnable 接口的 run 办法就能够实现多线程
// 函数式接口
@FunctionalInterface
public interface Runnable {public abstract void run();
}
Callable
很多人都晓得要想在多线程中获取异步返回值后果个别是用 Callable 和 FutureTask 接口来配合实现,但可能很多人都不晓得其实 Callable 是依赖于 Runnable 的 run 办法进行执行工作的,而后在通过 FutureTask 来收集返回值后果,上面咱们就本人模仿写一份 FutureTask 代码来看看是怎么实现的吧。
/**
* @author yinfeng
* @description 本人实现 futureTask,基于 park/unpark 进行线程通信
* @since 2022/1/9 21:32
*/
public class MyFutureTask<T> implements Runnable {
Callable<T> callable;
/**
* callable 执行后果
*/
T result;
/**
* task 执行状态
*/
String state = "new";
/**
* 存储正在期待的消费者
*/
LinkedBlockingQueue<Thread> waiters = new LinkedBlockingQueue<>();
public MyFutureTask(Callable<T> callable) {this.callable = callable;}
@Override
public void run() {
try {result = callable.call();
} catch (Exception e) {e.printStackTrace();
} finally {state = "end";}
// 工作执行实现后通过 unpark 告诉消费者
System.out.println(Thread.currentThread().getName() + "生产者执行完结,告诉消费者");
while (true) {Thread waiter = waiters.poll();
if (waiter == null) {break;}
LockSupport.unpark(waiter);
}
}
/**
* park / unpark
*/
public T get() throws Exception {Thread mainThread = Thread.currentThread();
// 塞入期待的汇合中
waiters.add(mainThread);
// 判断状态
System.out.println(Thread.currentThread().getName() + "消费者进入期待");
while (!"end".equals(state)) {
// 阻塞期待工作执行实现后告诉
LockSupport.park(mainThread);
}
return result;
}
}
咱们写个 demo 测试一下
/**
* @author yinfeng
* @description
* @since 2022/1/9 21:32
*/
public class FutureTaskTest {public static void main(String[] args) throws Exception {final MyFutureTask<String> futureTask = new MyFutureTask<>(() -> {Thread.sleep(5000);
return "工作实现 888";
});
new Thread(futureTask).start();
final String result = futureTask.get();
System.out.println("后果:"+result);
// 控制台打印如下:
// main 消费者进入期待
// Thread-0 生产者执行完结,告诉消费者
// 后果:工作实现 888
}
}
能够看到咱们的 demo 也是失常运行的,所以很要害的一点还是 Callable 是依赖于 Runnable 的 run 办法进行执行工作的