java多线程(3)之join与countDownLatch


join是Thread中的类,一般用于一个A线程需要等到另一个B线程的结果才可以继续执行的情形, 这是一种有序的执行方式,比如说主线程需要等到子线程返回的结果后才可以继续执行.
eg.

public class TestThread extends Thread {

    public TestThread(String name) {
        super(name);
    }

    @Override
    public void run() {
        try {
            for (int i=0;i<5;i++) {
                System.out.println(Thread.currentThread().getName()+":"+i);
            }
        } catch (Exception e) {

        }

    }
}


public class MultThreadTest {

    @Test
    public void test() {

        TestThread testThread1 = new TestThread("线程111111");
        testThread1.start();
        try {
            testThread1.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println(Thread.currentThread().getName() + ":执行结束");
    }
}

实现起来比较简单,调用testThread1.join()方法后,输出”执行结束”的语句需要等到testThread1线程执行完毕后才可以执行。如果把testThread1.join()去掉后就变成并发执行了。

thread.join源码解析

 public final void join() throws InterruptedException {
        join(0);
    }

     /**
     * Waits at most {@code millis} milliseconds for this thread to
     * die. A timeout of {@code 0} means to wait forever.
     *
     * <p> This implementation uses a loop of {@code this.wait} calls
     * conditioned on {@code this.isAlive}. As a thread terminates the
     * {@code this.notifyAll} method is invoked. It is recommended that
     * applications not use {@code wait}, {@code notify}, or
     * {@code notifyAll} on {@code Thread} instances.
     *
     * @param  millis
     *         the time to wait in milliseconds
     *
     * @throws  IllegalArgumentException
     *          if the value of {@code millis} is negative
     *
     * @throws  InterruptedException
     *          if any thread has interrupted the current thread. The
     *          <i>interrupted status</i> of the current thread is
     *          cleared when this exception is thrown.
     */
    public final void join(long millis) throws InterruptedException {
        synchronized(lock) {
        long base = System.currentTimeMillis();
        long now = 0;

        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }

        if (millis == 0) {
            while (isAlive()) {
                lock.wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                lock.wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
        }
    }

执行到if (millis == 0) {
while (isAlive()) {
lock.wait(0);
}
}里面做了两件事:判断线程是否存活,另外执行了lock.wait(0)方法进行阻塞,需等待到notify/notifyAll调用时才可以继续执行,然而notify()/notifyAll()方法什么时候执行的呢?

>

This implementation uses a loop of {@code this.wait} calls * conditioned on {@code this.isAlive}. As a thread terminates the * {@code this.notifyAll} method is invoked. It is recommended that * applications not use {@code wait}, {@code notify}, or * {@code notifyAll} on {@code Thread} instances.

这里的说明是说当线程停止的时候会调用notifyAll()方法,并且不推荐我们应用程序中的线程实例自身调用wait/notify/notifyAll()方法.这里就说明了当testThread1线程的run()方法执行结束的时候,会解除阻塞继续执行下去,执行到主线程,从而实现了线程间的有序执行。

countDownLatch的作用跟join差不多,也可以用来实现线程间协调工作,它的原理是利用“锁计数器”实现的,里面用到了CAS设计。如果完成一个工作需要n个线程并发执行,互不干扰,当这n个任务都完成后才能执行后续的操作,这时就可以设置锁计数器的个数为n,每完成一个任务锁计数器就减1,直到锁计数器为0所有任务完成后才继续执行后续的操作。这就是countDownLatch的原理

eg.

public class TestThread extends Thread {

    CountDownLatch latch;

    public TestThread(String name, CountDownLatch countDownLatch) {
        super(name);
        latch=countDownLatch;
    }

    @Override
    public void run() {
        try {
            for (int i = 0; i < 5; i++) {
                System.out.println(Thread.currentThread().getName() + ":" + i+"执行结束,锁计数器减1");
            }
            latch.countDown();
        } catch (Exception e) {

        }

    }
}


public class MultThreadTest {

    CountDownLatch countDownLatch;
    int tasks;

    @Before
    public void setUp(){
        tasks=3;
        countDownLatch=new CountDownLatch(tasks);
    }
    @Test
    public void test() {
        for (int i=0;i<tasks;i++){
            TestThread testThread = new TestThread("线程"+i+"执行",countDownLatch);
            testThread.start();
        }
        try {
            System.out.println(Thread.currentThread().getName()+":等待执行");
            countDownLatch.await();
            System.out.println(Thread.currentThread().getName() + ":执行结束");
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }
}

latch.countDown();每执行一次锁计数器减1,当锁计数器为0时,countDownlatch.await()不再阻塞,锁计数器大于0时会阻塞下去.


countDownLatch源码解析

countDownLatch构造函数:

 public CountDownLatch(int count) {
       if (count < 0) throw new IllegalArgumentException("count < 0");
        this.sync = new Sync(count);
    }


 private static final class Sync extends AbstractQueuedSynchronizer {
        private static final long serialVersionUID = 4982264981922014374L;

        Sync(int count) {
            setState(count);
        }

        int getCount() {
            return getState();
        }

构造函数中创建了Sync对象,Sync继承了AQS,这是countDownlatch核心实现!

countDownLatch instance中的countDown调用关系.

 public void countDown() {
        sync.releaseShared(1);
    }

    public final boolean releaseShared(int arg) {
        if (tryReleaseShared(arg)) {
            doReleaseShared();
            return true;
        }
        return false;
    }

     protected int tryAcquireShared(int acquires) {
            return (getState() == 0) ? 1 : -1;
        }

        protected boolean tryReleaseShared(int releases) {
            // Decrement count; signal when transition to zero
            for (;;) {
                int c = getState();
                if (c == 0)
                    return false;
                int nextc = c - 1;
                if (compareAndSetState(c, nextc))
                    return nextc == 0;
            }
        }


    private void doReleaseShared() {
           for (;;) {
            Node h = head;
            if (h != null && h != tail) {
                int ws = h.waitStatus;
                if (ws == Node.SIGNAL) {
                    if (!h.compareAndSetWaitStatus(Node.SIGNAL, 0))
                        continue;        // loop to recheck cases
                    unparkSuccessor(h);
                }
                else if (ws == 0 &&
                         !h.compareAndSetWaitStatus(0,Node.PROPAGATE))
                    continue;           // loop on failed CAS
            }
            if (h == head)             // loop if head changed
                break;
        }
    }

tips: tryReleaseShared()方法中for(;;)采用的自旋方法来比较设置compareAndSetState(),这是很常见的CAS方式java多线程(二)之CAS操作.countDownLatch每执行一次countDown(),就会不断的尝试释放锁, compareAndSetState执行成功,就会修改一次锁计数减1,当锁计数器为0时执行doReleaseShared(),唤醒后面队列中的的节点线程。

countDownLatch instance中的await()调用关系.


public void await() throws InterruptedException {
        sync.acquireSharedInterruptibly(1);
    }


    public final void acquireSharedInterruptibly(int arg)
            throws InterruptedException {
        if (Thread.interrupted())
            throw new InterruptedException();
        if (tryAcquireShared(arg) < 0)
            doAcquireSharedInterruptibly(arg);
    }

    protected int tryAcquireShared(int acquires) {
            return (getState() == 0) ? 1 : -1;
        }



    private void doAcquireSharedInterruptibly(int arg)
        throws InterruptedException {
        final Node node = addWaiter(Node.SHARED);
        try {
            for (;;) {
                final Node p = node.predecessor();
                if (p == head) {
                    int r = tryAcquireShared(arg);
                    if (r >= 0) {
                        setHeadAndPropagate(node, r);
                        p.next = null; // help GC
                        return;
                    }
                }
                if (shouldParkAfterFailedAcquire(p, node) &&
                    parkAndCheckInterrupt())
                    throw new InterruptedException();
            }
        } catch (Throwable t) {
            cancelAcquire(node);
            throw t;
        }
    }

   ... 

进入到doAcquireSharedInterruptibly(arg)方法进行等待,当getState()==0时结束,countDownLatch()后面的语句继续执行.countDownLatch类大致的源码调用流程分析完了,有什么不足欢迎大家在下方留言指正,不胜感激.


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值