现在的位置: 首页 > 综合 > 正文

通过Thread.join()和CountDownLatch来实现进程同步

2018年09月29日 ⁄ 综合 ⁄ 共 2501字 ⁄ 字号 评论关闭

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.

抱歉!评论已关闭.