实现多线程间通信的FutureTask,我们来手写一个

实现多线程间通信的FutureTask,我们来手写一个

点击上方蓝字关注我!


Callable实现线程通信

我们先来温习下如何让创建多线程:

1.继承Thread

2.实现Runnable

3.调用Callable

4.使用线程池ThreadPoolExecutor

我们在平时的开发中肯定遇到过【B线程如何获取A线程中的数据】,经验老道的程序员首先会想到使用Callable实现。直接看代码:

实现多线程间通信的FutureTask,我们来手写一个

如上图,线程A【Thread-0】里面存入了字符串【Lvshen的技术小屋】。我们要在主线程【main】获取这个值,就采用如上方法。测试结果如下:

10:51:12.756 [Thread-0] INFO com.lvshen.demo.thread.future.Test - 当前线程:Thread-0
当前线程:[main],取出的值:[Lvshen的技术小屋]

FutureTask

细心的你肯定看到了这段代码

FutureTask<String> myFutureTask = new FutureTask<>(callable);

数据是从FutureTask里面取出的,那么FutureTask是个什么东东?

FutureTask类是Future的实现,它同时也实现了Runnable,因此也可以被Executor执行。

继承树如下:

实现多线程间通信的FutureTask,我们来手写一个

那么FutureTask有什么特点呢?

  • 一个可取消的异步任务
  • 该类提供了Future的基本实现,提供了启动和取消计算、查询计算是否完成以及检索计算结果的方法
  • 只有在计算完成后才可检索结果;如果计算尚未完成,get方法将阻塞
  • 计算完成以后,计算不能重启或取消(除非调用runAndReset方法)

一个FutureTask可以用来包装一个CallableRunnable对象。因为FutureTask实现了Runnable接口,一个FutureTask可以被提交给一个Executor来执行。

这里我们简单看下get()方法为什么能获取到其他线程的值。

首先创建FutureTask,设置状态为NEW

实现多线程间通信的FutureTask,我们来手写一个

get()为阻塞获取。

实现多线程间通信的FutureTask,我们来手写一个

awaitDone()为线程阻塞的方法,再来看看report()方法:

实现多线程间通信的FutureTask,我们来手写一个其中outcome就是我们要获取的值。outcome值来源于set()方法。

实现多线程间通信的FutureTask,我们来手写一个

当线程start时,会调用FutureTaskrun()方法,这里注意两个地方:

1.result的值为call()方法的返回值

2.result会存进set()方法中

实现多线程间通信的FutureTask,我们来手写一个

手写FutureTask

我们大概了解了FutureTask的结构,不如我们来手写一个FutureTask吧😀。

首先定义一个MyFutureTask类并实现Runnable接口

public class MyFutureTask<Timplements Runnable {
   ...
}

然后定义几个属性

Callable<T> callable;

T result;

volatile String state = "NEW";

LinkedBlockingQueue<Thread> queue = new LinkedBlockingQueue<Thread>();

需要一个callable对象,用来接收外面传进来的callableresult接收call()方法返回的值;”NEW”为初始状态,用作标记;queue为阻塞队列,用于存放当前线程。

定义构造函数:

public MyFutureTask(Callable<T> callable) {
    this.callable = callable;
}

定义get()方法:

public T get() {
    if ("END".equals(state)) {
        return result;
    }

    while (!"END".equals(state)) {
        queue.add(Thread.currentThread());
        LockSupport.park();
    }
    return result;
}

队列中添加一次线程,阻塞一次当前线程。

@Override
public void run() {

    try {
        result = callable.call();
    } catch (Exception e) {
        e.printStackTrace();
    } finally {
        state = "END";
    }

    Thread th = queue.poll();
    if (queue != null) {
        LockSupport.unpark(th);
        th = queue.poll();
    }
}

启动线程时会调用run()方法,callable.call()获取线程中存入的值并赋值给result,从队列中取出线程,如果有值,解锁当前线程,然后继续取值。

我么来测试一下:

实现多线程间通信的FutureTask,我们来手写一个

测试结果:

实现多线程间通信的FutureTask,我们来手写一个

效果已经达到。如果需要源码可以到我的github下载

https://github.com/lvshen9/demo/blob/lvshen-dev/src/main/java/com/lvshen/demo/thread/future





往期推荐




实现多线程间通信的FutureTask,我们来手写一个
实现多线程间通信的FutureTask,我们来手写一个

扫码二维码

获取更多精彩

Lvshen_9

实现多线程间通信的FutureTask,我们来手写一个
实现多线程间通信的FutureTask,我们来手写一个

原文始发于微信公众号(Lvshen的技术小屋):实现多线程间通信的FutureTask,我们来手写一个

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/262609.html

(0)
Java朝阳的头像Java朝阳

相关推荐

发表回复

登录后才能评论
极客之音——专业性很强的中文编程技术网站,欢迎收藏到浏览器,订阅我们!