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类大致的源码调用流程分析完了,有什么不足欢迎大家在下方留言指正,不胜感激.
- java多线程(3)之join与countDownLatch
- java 多线程 CountDownLatch与join()方法区别
- java多线程Thread join与CountDownLatch源码分析
- Java多线程之CountDownLatch
- Java多线程之CountDownLatch
- Java多线程之CountDownLatch
- JAVA多线程之CountDownLatch
- Java多线程之CountDownLatch
- Java多线程之CountDownLatch
- Java多线程之CountDownLatch
- Java多线程之----CountDownLatch
- Java多线程之CountDownLatch
- java多线程之CountDownLatch
- java多线程之CountDownLatch
- 多线程计数器之CountDownLatch和join
- 多线程计数器之CountDownLatch和join
- 多线程CountDownLatch和Join
- 【java多线程】CountDownLatch与CyclicBarrier
- 一个服务器上运行多个tomcat,显示总启动某一个特定tomcat
- 第十课记录 MapReduce编程模型与案例
- XZ_JavaScript之JavaScript的两大内置对象
- 处理器管理-进程的状态
- php页面静态化实现思路
- java多线程(3)之join与countDownLatch
- 如何保证Redis中的数据都是热点数据
- PHP数据库保存html和php标签正常显示
- logback高级特性使用(二)
- 全球各地仍有40亿人口还是无法上网
- (译)Java Concurrent系列--BlockingQueue
- SQLServer--简单子查询
- LayoutParams
- ios 基础知识点总结 (二)