11.join和futureTask源码

85 阅读2分钟

join源码

//注意这里加锁了 锁的对象是当前调用join方法的对象 即this
public final synchronized void join(long millis)throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;
​
        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }
​
        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            //如果线程还在存活 那么死循环
            while (isAlive()) {
                long delay = millis - now;
                //如果带有等待超时时间的join
                //并且超时时间已经过去了
                //那么直接跳出死循环 join方法结束
                if (delay <= 0) {
                    break;
                }
                //带有等待超时时间的join
                //即使在这里错误被唤醒
                //只要线程是alive状态,会重新进入循环继续阻塞等待。
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

线程是如何被阻塞的?又是通过什么方法唤醒的呢?先来看看Thread.join方法做了什么事情

从join方法的源码来看,join方法的本质调用的是Object中的wait方法实现线程的阻塞。但是我们需要知道的是,调用wait方法必须要获取锁,所以join方法是被synchronized修饰的,synchronized修饰在方法层面相当于synchronized(this),this就是previousThread本身的实例。

有很多人不理解join为什么阻塞的是主线程呢?

不理解的原因是阻塞主线程的方法是放在previousThread这个实例作用,让大家误以为应该阻塞previousThread线程。

实际上主线程会持有previousThread这个对象的锁,然后调用wait方法去阻塞,而这个方法的调用者是在主线程中的。所以造成主线程阻塞。

为什么previousThread线程执行完毕就能够唤醒住线程呢?或者说是在什么时候唤醒的?

因为线程执行完毕以后isAlive()是false。 就会跳出死循环。join代码执行结束。

Thread 与 Runnable 的关系

Thread实现了runnable接口重写了run方法并且拥有一个Runnable的变量。

Thread持有一个属性Runnable叫target,调用start方法时,判断target是否存在,如果存在优先调用target的run方法,否则调用子类重写的run方法。

如果使用的是Thread子类 需要重写run方法,

如果使用的是Thread和Runnable,那么调用的是runnable的run方法

public class Thread implements Runnable {
  private Runnable target;  
 @Override
    public void run() {
        if (target != null) {
            target.run();
        }
    }
}

原理:FutureTask的底层实现:适配器

FutureTask implements RunnableFuture

RunnableFuture extends Runnable, Future

这就解释了为什么FutureTask可以放在Thread中执行了

new Thread(futureTask, "futureTask").start();

FutureTask#构造方法

    public FutureTask(Callable<V> callable) {
        if (callable == null)
            throw new NullPointerException();
        this.callable = callable;
        this.state = NEW;       // ensure visibility of callable
    }
     
    public FutureTask(Runnable runnable, V result) {
        //runnable适配成了callable
        this.callable = Executors.callable(runnable, result);
        this.state = NEW;       // ensure visibility of callable
    }
    //创建了一个RunnableAdapter
    public static <T> Callable<T> callable(Runnable task, T result) {
        if (task == null)
            throw new NullPointerException();
        return new RunnableAdapter<T>(task, result);
    }
    //发现RunnableAdapter实现了Callable
    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;
        }
        //默认的call方法实现调用的是 runnable的run
        public T call() {
            task.run();
            return result;
        }
    }

FutureTask#run

FutureTask实现了Runnable接口,并且实现了自己的run方法。

public void run() {
        if (state != NEW ||
            !UNSAFE.compareAndSwapObject(this, runnerOffset,
                                         null, Thread.currentThread()))
            return;
        try {
            //获取本类中的callable属性
            Callable<V> c = callable;
            if (c != null && state == NEW) {
                V result;
                boolean ran;
                try {
                    //调用的是callable的call方法
                    result = c.call();
                    //执行完设置执行完成标记 
                    ran = true;
                } catch (Throwable ex) {
                    result = null;
                    ran = false;
                    setException(ex);
                }
                if (ran)
                    //重点!!!!
                    //调用set方法
                    set(result);
            }
        } finally {
            runner = null;
            int s = state;
            if (s >= INTERRUPTING)
                handlePossibleCancellationInterrupt(s);
        }
    }

FutureTask#set:修改状态为完成后唤醒

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

LockSupport.unpark(t);在这里将之前阻塞的线程unpark。

 private void finishCompletion() {
        // assert state > COMPLETING;
        for (WaitNode q; (q = waiters) != null;) {
            if (UNSAFE.compareAndSwapObject(this, waitersOffset, q, null)) {
                for (;;) {
                    Thread t = q.thread;
                    if (t != null) {
                        q.thread = null;
                        //在call方法运行期间 即 还没有返回值返回
                        //这个时候调用get方法获取结果
                        // LockSupport.park(this);
                        LockSupport.unpark(t);
                    }
                    WaitNode next = q.next;
                    if (next == null)
                        break;
                    q.next = null; // unlink to help gc
                    q = next;
                }
                break;
            }
        }
        //空实现 扩展方法 模板模式
        done();
        callable = null;        // to reduce footprint
    }

FutureTask#get:根据状态:等待还是立刻返回

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

如果不是完成状态COMPLETING就会调用awaitDone继续Park

   private int awaitDone(boolean timed, long nanos)
        throws InterruptedException {
        final long deadline = timed ? System.nanoTime() + nanos : 0L;
        WaitNode q = null;
        boolean queued = false;
        for (;;) {
            //如果调用get方法的线程被打断
            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);
        }
    }

重点来了,这里是一个死循环,然后判断了一个状态,调用了LockSupport.park方法让这个线程阻塞,就是说你get的时候,如果我没执行完,那你就在这等着我执行完。

也就是说其他的线程调用本线程的LockSupport.unpark也不会让本线程退出等待,而是会在下一轮循环继续等待。

比如下面的t1

//先 park 再 unpark:先暂停再继续往下执行
Thread t1 = new Thread(() -> {
    //t1在get方法中被Park方法阻塞
     futureTask.get();
}
,"t1");
t1.start();
sleep(2);
//即使这里t1被unpark
//也会在死循环中立刻又被Park
LockSupport.unpark(t1);
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);
    }