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