java多线程(3)之join与countDownLatch

来源:互联网 发布:如何安装php开发环境 编辑:程序博客网 时间:2024/04/30 13:28

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类大致的源码调用流程分析完了,有什么不足欢迎大家在下方留言指正,不胜感激.


原创粉丝点击