• 欢迎访问搞代码网站,推荐使用最新版火狐浏览器和Chrome浏览器访问本网站!
  • 如果您觉得本站非常有看点,那么赶紧使用Ctrl+D 收藏搞代码吧

关于java:Future-Java

java 搞代码 4年前 (2022-01-28) 16次浏览 已收录 0个评论
文章目录[隐藏]

摘要

  1. 什么是Future
  2. 为什么须要Future
  3. Java中的Future模式
  4. 详解FutureTask

1. 什么是Future

Future是多线程开发中常见的一种设计模式。Future模式能够返回线程执行后果的契约,通过此契约程序能够抉择在适合的机会取回执行的后果,如果取回后果时线程还没有执行实现,将会阻塞调用线程期待执行后果返回。

2. 为什么须要Future

在有些场景下,咱们想应用另一个线程去执行简单耗时的操作,此时又不想让主线程期待白白浪费CPU,此时能够让主线程先去做别的事,而后在适合的机会去通过Future契约取回线程执行的后果。

3. Java中的Future模式

Java中的Future模式次要由以上接口和类组成。

3.1 Callable & Runnable

这是咱们一般的线程工作,其中Callable是带返回来源gao($daima.com搞@代@#码网值(实在数据),Runnable是不带返回值的,因而在咱们应用Runnable和Future时,必须传入一个Result对象,通过Future在获取后果时就是获取的该Result,外围代码如下:

<code class="java">public FutureTask(Runnable runnable, V result) {
    this.callable = Executors.callable(runnable, result);
    this.state = NEW;       // ensure visibility of callable
}

public static <T> Callable<T> callable(Runnable task, T result) {
    if (task == null)
        throw new NullPointerException();
    return new RunnableAdapter<T>(task, result);
}

static final class RunnableAdapter<T> implements Callable<T> {
    final Runnable task;
    final T result;
    RunnableAdapter(Runnable task, T result) {
        this.task = task;
        this.result = result;
    }
    public T call() {
        task.run();
        return result;
    }
}

Callable目前只能搭配线程池或者Future来应用,不能间接和new Thread()搭配应用,Runnable能够搭配线程池和new Thread()应用,在配合Future应用时实质上是对其进行了适配,也就是上述代码中的RunnableAdapter。

3.2 Future

<code class="java">public interface Future<V> {

    boolean cancel(boolean mayInterruptIfRunning);
    boolean isCancelled();
    boolean isDone();
    V get() throws InterruptedException, ExecutionException;
    V get(long timeout, TimeUnit unit)
        throws InterruptedException, ExecutionException, TimeoutException;
}

Future是线程的契约,通过其get()办法咱们能够获取线程执行的后果,当然Future也提供了其余三个办法,别离是:

  • cancel:勾销工作
  • isCancelled:工作是否曾经勾销
  • isDone:工作是否实现

3.3 RunnableFuture

<code class="java">public interface RunnableFuture<V> extends Runnable, Future<V> {

    void run();
}

RunnableFuture接口继承自Runnable和Future,表明RunnableFuture能够被线程执行并且能够通过契约获取到线程的执行后果。

4. FutureTask

4.1 属性

<code class="java">// 执行工作
private Callable<V> callable;
// 工作的理论执行后果
private Object outcome; 
// 执行工作的线程
private volatile Thread runner;
// 期待后果的线程栈
private volatile WaitNode waiters;

4.2 状态

<code class="java">private volatile int state;
private static final int NEW          = 0;
private static final int COMPLETING   = 1;
private static final int NORMAL       = 2;
private static final int EXCEPTIONAL  = 3;
private static final int CANCELLED    = 4;
private static final int INTERRUPTING = 5;
private static final int INTERRUPTED  = 6;

FutureTask除了4.1中的属性外,还有一个重要的属性就是state,FutureTask中的状态大概有7种:

  • NEW:工作的初始状态
  • COMPLETING:正在设置工作后果
  • NORMAL:工作执行结束
  • EXCEPTIONAL:工作发行异样
  • CANCELLED:工作被勾销
  • INTERRUPTING:正在中断工作
  • INTERRUPTED:工作被中断

4.3 run()办法

工作执行的时候理论就是执行run办法,源码如下:

<code class="java">public void run() {
    if (state != NEW ||
        !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                     null, Thread.currentThread()))
        return;
    try {
        Callable<V> c = callable;
        if (c != null && state == NEW) {
            V result;
            boolean ran;
            try {
                result = c.call();
                ran = true;
            } catch (Throwable ex) {
                result = null;
                ran = false;
                setException(ex);
            }
            if (ran)
                set(result);
        }
    } finally {
        // runner must be non-null until state is settled to
        // prevent concurrent calls to run()
        runner = null;
        // state must be re-read after nulling runner to prevent
        // leaked interrupts
        int s = state;
        if (s >= INTERRUPTING)
            handlePossibleCancellationInterrupt(s);
    }
}

protected void set(V v) {
    if (UNSAFE.compareAndSwapInt(this, stateOffset, NEW, COMPLETING)) {
        outcome = v;
        UNSAFE.putOrderedInt(this, stateOffset, NORMAL); // final state
        finishCompletion();
    }
}

private void handlePossibleCancellationInterrupt(int s) {
    // It is possible for our interrupter to stall before getting a
    // chance to interrupt us.  Let's spin-wait patiently.
    if (s == INTERRUPTING)
        while (state == INTERRUPTING)
            Thread.yield(); // wait out pending interrupt
}

run办法的大抵流程如下:

  1. 校验工作的状态是否是NEW和以后是否无执行线程,如果校验通过,则获取工作执行
  2. 调用工作的call办法
  3. 如果执行异样,设置后果,状态批改为EXCEPTIONAL,并将工作后果设置为异样
  4. 如果失常执行,调用set(V v)设置后果,状态批改为NORMAL,后果设置为执行后果,并且唤醒期待后果的线程
  5. 最初在finally块中,咱们将runner属性置为null,并且查看有没有脱漏的中断,如果发现s >= INTERRUPTING, 阐明执行工作的线程有可能被中断了,因为s >= INTERRUPTING 只有两种可能,state状态为INTERRUPTING和INTERRUPTED。

4.3 get()办法

当咱们须要去获取FutureTask的后果时,咱们须要调用get办法获取后果。

<code class="java">
public V get() throws InterruptedException, ExecutionException {
    int s = state;
    if (s <= COMPLETING)
        s = awaitDone(false, 0L);
    return report(s);
}

@SuppressWarnings("unchecked")
private V report(int s) throws ExecutionException {
    Object x = outcome;
    if (s == NORMAL)
        return (V)x;
    if (s >= CANCELLED)
        throw new CancellationException();
    throw new ExecutionException((Throwable)x);
}

private int awaitDone(boolean timed, long nanos)
    throws InterruptedException {
    final long deadline = timed ? System.nanoTime() + nanos : 0L;
    WaitNode q = null;
    boolean queued = false;
    for (;;) {
        if (Thread.interrupted()) {
            removeWaiter(q);
            throw new InterruptedException();
        }

        int s = state;
        if (s > COMPLETING) {
            if (q != null)
                q.thread = null;
            return s;
        }
        else if (s == COMPLETING) // cannot time out yet
            Thread.yield();
        else if (q == null)
            q = new WaitNode();
        else if (!queued)
            queued = UNSAFE.compareAndSwapObject(this, waitersOffset,
                                                 q.next = waiters, q);
        else if (timed) {
            nanos = deadline - System.nanoTime();
            if (nanos <= 0L) {
                removeWaiter(q);
                return state;
            }
            LockSupport.parkNanos(this, nanos);
        }
        else
            LockSupport.park(this);
    }
}

获取后果的大抵步骤如下:

  1. 检测工作状态是否是NEW或者COMPLETING,如果不是,阐明曾经执行胜利或失败,返回后果
  2. 否则就阻塞期待,阻塞期待的步骤如下
  3. 检测以后线程是否被中断,如果是就将其从期待线程中移除
  4. 再次检测工作状态,如果是异样、中断或者执行实现状态,则间接返回后果。
  5. 如果工作是COMPLETING状态,阐明工作曾经执行实现正在设置后果,此时让获取后果的线程短暂让出CPU持续期待
  6. 如果期待后果的线程栈为null,阐明还没有生成,则生成期待后果的线程栈
  7. 如果queued为false,阐明期待后果的线程还没入栈,所以将其入栈
  8. 最初看是否是是超时期待,依据是否超时,抉择将期待后果的线程永恒挂起(期待唤醒)还是具备超时工夫的挂起

本期的Java Future就介绍到这,我是shysh95,咱们下期再见!


搞代码网(gaodaima.com)提供的所有资源部分来自互联网,如果有侵犯您的版权或其他权益,请说明详细缘由并提供版权或权益证明然后发送到邮箱[email protected],我们会在看到邮件的第一时间内为您处理,或直接联系QQ:872152909。本网站采用BY-NC-SA协议进行授权
转载请注明原文链接:关于java:Future-Java

喜欢 (0)
[搞代码]
分享 (0)
发表我的评论
取消评论

表情 贴图 加粗 删除线 居中 斜体 签到

Hi,您需要填写昵称和邮箱!

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址