1.Thread.join()
如果在一个进程,如main中调用另一个thread的join()函数会导致main函数阻塞,直至thread执行完毕。
public class JoinTest {
public static void main(String[] args) {
System.out.println("main starts.");
Thread thread = new Thread(new Runnable() {
public void run() {
for(int i = 0;i < 5;i++){
try {
System.out.println("thread" + i + " starts.");
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
});
thread.start();
try {
thread.join();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("main ends.");
}
}
输出结果为:
main starts.
thread0 starts.
thread1 starts.
thread2 starts.
thread3 starts.
thread4 starts.
main ends.
从输出结果来看,main线程打印了main starts,执行到thread.join()被阻塞了,此时子线程开始打印log,且打印间隔为500ms,当子线程执行完毕后,main线程打印输出main ends。
如果我们将thread.join()改成thread.join(1500),那么输出结果如下:
main starts.
thread0 starts.
thread1 starts.
thread2 starts.
main ends.
thread3 starts.
thread4 starts.
这里采用的是join的一个重载方法,join(long millis),表示等到线程thread执行完毕或者阻塞millis时间后才能允许调用这个函数的线程继续执行下去。从上述输出中我们可以看出main线程并没有等待thread执行完毕,而是等待了1500ms就继续执行了。
其实,这里还可以用这种方法来实现main线程等待thread线程:
//try {
// thread.join();
//} catch (InterruptedException e) {
// e.printStackTrace();
//}
while(thread.isAlive()){
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
判断thread是否处于alive状态,如果是那么main线程休眠100ms,如果thread结束了,main再继续执行。
2.CountDownLatch
CountDownLatch中维护了一个计数器,初始化时接受一个整型值作为计数器初始值,其中包括两个函数await和countDown,当在某个函数中调用await时,该线程被阻塞,没调用一次countDown计数器值减一,只有当计数器的值为0的时候刚才被阻塞的线程才能继续向下执行。
public class CountDownLatchTest {
public static void main(String[] args) throws InterruptedException {
final CountDownLatch startCdt = new CountDownLatch(5);
final CountDownLatch endCdt = new CountDownLatch(5);
for(int i = 0; i < 5; i++){
new Thread(new Runnable(){
public void run() {
System.out.println(Thread.currentThread().getName() + "starts.");
try {
startCdt.countDown();
startCdt.await(); //创建的5个线程都在等startCdt的count=0才继续往下执行
} catch (InterruptedException e) {
e.printStackTrace();
}finally{
endCdt.countDown(); //每个线程执行完后都将count值减1
System.out.println(Thread.currentThread().getName() + " ends.");
}
}
}).start();
}
endCdt.await();
//main线程当endCdt的值为0时才继续执行,也就是等上边创建的5个线程执行完毕后才继续执行
System.out.println("all threads end.");
}
执行结果如下:
Thread-1starts.
Thread-3starts.
Thread-4starts.
Thread-2starts.
Thread-0starts.
Thread-0 ends.
Thread-1 ends.
Thread-3 ends.
Thread-4 ends.
Thread-2 ends.
all threads end.
尽管每个子线程创建后立刻执行,但是当他们在运行到startCdt.await()时都被阻塞了,只有startCdt的计数器的值减为0时才继续向下执行;同理main线程在执行到endCdt.await()时阻塞,只有当其计数器减为0时才继续执行。如果没有endCdt.await(),那么执行结果如下:
Thread-1starts.
Thread-4starts.
Thread-0starts.
all threads end.
Thread-2starts.
Thread-3starts.
Thread-3 ends.
Thread-1 ends.
Thread-4 ends.
Thread-0 ends.
Thread-2 ends.