1.首先我们基于原生的Callable、FutureTask实现主线程 获取子线程的执行结果
定义MyCallable实现Callable接口
- import java.util.concurrent.Callable;
-
- public class MyCallable implements Callable {
- @Override
- public Integer call() throws Exception {
- Thread.sleep(3000);
- return 1;
- }
- }
编写测试类
- import java.util.concurrent.ExecutionException;
- import java.util.concurrent.FutureTask;
-
- public class Test {
- public static void main(String[] args) throws ExecutionException, InterruptedException {
- MyCallable myCallable = new MyCallable();
- FutureTask futureTask = new FutureTask<>(myCallable);
- new Thread(futureTask).start();
-
- Object o = futureTask.get();//执行get方法 主线程阻塞
- System.out.println(o);
- }
- }
运行测试,主线程阻塞3s,等子线程执行完毕后,主线程才能继续往下执行
原理:执行futureTask.get()时,主线程进入阻塞状态,子线程执行完毕后,再唤醒主线程,主线程能拿到子线程的返回值
2.手写代码实现以上效果
分析上述的代码,我们这里定义三个类:
- public interface MyCallable
{ - V call() throws Exception;
- }
- public class MyCallableImpl implements MyCallable{
- @Override
- public Integer call() throws Exception {
- //模拟耗时任务
- Thread.sleep(3000);
- return 1;
- }
- }
- public class MyFutureTask
implements Runnable{ - private MyCallable
myCallable; - private V result = null;
-
- public MyFutureTask(MyCallable
myCallable) { - this.myCallable = myCallable;
- }
-
- public V get(){
- synchronized (this){
- try {
- //主线程执行到这里 进入阻塞状态
- this.wait();
- } catch (InterruptedException e) {
- e.printStackTrace();
- }
- }
- return result;
- }
-
- @Override
- public void run() {
- try {
- V call = myCallable.call();
- //拿到子线程的执行结果
- result = call;
- //子线程执行完毕 唤醒主线程
- synchronized (this){
- this.notify();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
编写测试类运行
- public class Test {
-
- public static void main(String[] args) {
- MyCallableImpl myCallable = new MyCallableImpl();
- MyFutureTask
myFutureTask = new MyFutureTask(myCallable); - //开启子线程
- new Thread(myFutureTask).start();
- //调用get方法 主线程进入阻塞 当子线程任务执行完毕 主线程才被唤醒 继续往下执行
- Integer result = myFutureTask.get();
- System.out.println(result);
- }
-
- }
效果同原生代码一致,主线程阻塞3s,等子线程执行完毕之后 主线程才继续往下执行
3.我们基于LockSupport.park() 、unpark()改进一下序号2中的代码,原理同synchronized中的wait、notify一致
在第二步中我们定义的三个类,只有MyFutureTask需要修改,代码如下
- import java.util.concurrent.locks.LockSupport;
-
- public class MyFutureTask
implements Runnable{ - private MyCallable
myCallable; - private V result = null;
- //thread为主线程对象
- private Thread thread = null;
-
- public MyFutureTask(MyCallable
myCallable) { - this.myCallable = myCallable;
- }
-
- public V get(){
- //thread为主线程 因为get()方法是在主线程中执行
- thread = Thread.currentThread();
- //主线程阻塞
- LockSupport.park();
- return result;
- }
-
- @Override
- public void run() {
- try {
- V call = myCallable.call();
- //拿到子线程的执行结果
- result = call;
- //子线程执行完毕 唤醒主线程
- LockSupport.unpark(thread);
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
测试类同序号2中一致,直接运行验证即可