JAVA线程分组顺序执行

             通过初步学习多线程后,知道如果新启动一个线程,新线程会独立执行任务,当前线程会继续往下执行。有时我们有这样的要求,必须等新线程执行完后,当前线程才能继续往下执行。满足这样的需求,JAVA中有多种方法。

1.join()方法

        在线程中,可以使用join()方法让一个线程强制运行,线程强制运行期间其它线程无法运行,必须等待此线程完成后才可以继续执行。

package cn.thread;

public class ThreadJoinTest {
	
	private final static int GROUP_SIZE = 5;

	public static void main(String []args) throws InterruptedException {
		Thread [] threadGroup1 = new Thread[GROUP_SIZE];
		Thread [] threadGroup2 = new Thread[GROUP_SIZE];
		createThreadGroup(threadGroup1,"第1线程组");
		createThreadGroup(threadGroup2,"第2线程组");
		//启动第1线程组
		startThreadGroup(threadGroup1);
		//阻塞当前线程,等待第1线程组全部执行完毕
		joinThreadGroup(threadGroup1);
		System.out.println("第1线程组全部执行完毕!!!!!!!!");
		//启动第2线程组
		startThreadGroup(threadGroup2);
		//阻塞当前线程,等待第2线程组全部执行完毕
		joinThreadGroup(threadGroup2);
		System.out.println("第2线程组全部执行完毕!!!!!!!!");
	}
	
	private static void createThreadGroup(Thread[] group,final String name){
		for(int i=0;i<group.length;i++){
			final int num=i+1;
			group[i]=new Thread(){
				public void run(){
					for(int j=1;j<=5;j++){
						System.out.println("我是"+name+" "+num+"号"+"第"+j+"次运行.....");
					}
				}
			};
		}
	}
	private static void startThreadGroup(Thread[] group){
		for(Thread t:group){
			t.start();
		}
	}
	private static void joinThreadGroup(Thread[] group){
		for(Thread t:group){
			try {
				t.join();//强制让线程t运行
			} catch (InterruptedException e) {
				e.printStackTrace();
			}
		}
	}
}


运行结果

我是第1线程组 1号第1次运行.....
我是第1线程组 1号第2次运行.....
我是第1线程组 1号第3次运行.....
我是第1线程组 1号第4次运行.....
我是第1线程组 1号第5次运行.....
我是第1线程组 2号第1次运行.....
我是第1线程组 2号第2次运行.....
我是第1线程组 2号第3次运行.....
我是第1线程组 2号第4次运行.....
我是第1线程组 2号第5次运行.....
我是第1线程组 3号第1次运行.....
我是第1线程组 3号第2次运行.....
我是第1线程组 3号第3次运行.....
我是第1线程组 3号第4次运行.....
我是第1线程组 4号第1次运行.....
我是第1线程组 4号第2次运行.....
我是第1线程组 4号第3次运行.....
我是第1线程组 4号第4次运行.....
我是第1线程组 4号第5次运行.....
我是第1线程组 5号第1次运行.....
我是第1线程组 5号第2次运行.....
我是第1线程组 5号第3次运行.....
我是第1线程组 5号第4次运行.....
我是第1线程组 5号第5次运行.....
我是第1线程组 3号第5次运行.....
第1线程组全部执行完毕!!!!!!!!
我是第2线程组 1号第1次运行.....
我是第2线程组 1号第2次运行.....
我是第2线程组 1号第3次运行.....
我是第2线程组 3号第1次运行.....
我是第2线程组 3号第2次运行.....
我是第2线程组 3号第3次运行.....
我是第2线程组 3号第4次运行.....
我是第2线程组 3号第5次运行.....
我是第2线程组 2号第1次运行.....
我是第2线程组 2号第2次运行.....
我是第2线程组 2号第3次运行.....
我是第2线程组 2号第4次运行.....
我是第2线程组 2号第5次运行.....
我是第2线程组 4号第1次运行.....
我是第2线程组 4号第2次运行.....
我是第2线程组 4号第3次运行.....
我是第2线程组 1号第4次运行.....
我是第2线程组 4号第4次运行.....
我是第2线程组 1号第5次运行.....
我是第2线程组 5号第1次运行.....
我是第2线程组 5号第2次运行.....
我是第2线程组 5号第3次运行.....
我是第2线程组 5号第4次运行.....
我是第2线程组 5号第5次运行.....
我是第2线程组 4号第5次运行.....
第2线程组全部执行完毕!!!!!!!!

2.CountDownLatch

     CountDownLatch主要起倒计时计数器作用,它主要有两个方法await()和countDown()。一旦某个线程调用await()方法,那么该线程就会阻塞,等待CountDownLatch计数器倒计时归零,需要注意的是尽管线程调用await()方法后会阻塞,但是CountDownLatch允许别的线程调用countDown()方法,将计数器减一。也就是说调用计时器的线程阻塞后,可以利用别的线程控制调用线程何时从新开始运行。

   CountDownLatch 是一个通用同步工具,它有很多用途。将计数 1 初始化的CountDownLatch 用作一个简单的开/关锁存器,或入口:在通过调用 countDown() 的线程打开入口前,所有调用await 的线程都一直在入口处等待。用 N 初始化的 CountDownLatch 可以使一个线程在 N个线程完成某项操作之前一直等待,或者使其在某项操作完成 N 次之前一直等待。

     CountDownLatch 的一个有用特性是,它不要求调用countDown 方法的线程等到计数到达零时才继续,而在所有线程都能通过之前,它只是阻止任何线程继续通过一个 await

 

package cn.thread;

import java.util.concurrent.CountDownLatch;

/**
 * 模拟运动员跑步
 * 同组的运动必须都准备就绪后才能出发
 *
 */
public class CountDownLatchTest {
	
	private final static int GROUP_SIZE = 5;
	
	public static void main(String []args) {
		processOneGroup("分组1");
		processOneGroup("分组2");
	}
	
	private static void processOneGroup(final String groupName) {
		final CountDownLatch start_count_down = new CountDownLatch(1);//起到锁的作用
		final CountDownLatch end_count_down = new CountDownLatch(GROUP_SIZE);//模拟运动员计数器
		System.out.println( groupName + "比赛开始:");
		for(int i = 0 ; i < GROUP_SIZE ; i++) {
			new Thread(String.valueOf(i)) {
				public void run() {
					System.out.println("【" + groupName + "】,第" + this.getName() + " 号线程,我已经准备就绪!");
					try {
						start_count_down.await();//进行阻塞,等待其他运动员准备就绪
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println("【" + groupName + "】,第" + this.getName() + " 号线程,我已执行完成!");
					end_count_down.countDown();//其中一个运动员完成,计算器-1
				}
			}.start();
		}
		try {
			Thread.sleep(1000);//让所有运动都准备好
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(groupName+"预备!Go!!!");
		start_count_down.countDown();//解锁,运动员开始赛跑
		try {
			end_count_down.await();//阻塞父线程,等到所有运动员跑完后(end_count_down为0),再往下执行
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println( groupName + "比赛结束!");
	}
}


运行结果

分组1比赛开始:
【分组1】,第0 号线程,我已经准备就绪!
【分组1】,第2 号线程,我已经准备就绪!
【分组1】,第3 号线程,我已经准备就绪!
【分组1】,第1 号线程,我已经准备就绪!
【分组1】,第4 号线程,我已经准备就绪!
分组1预备!Go!!!
【分组1】,第0 号线程,我已执行完成!
【分组1】,第1 号线程,我已执行完成!
【分组1】,第4 号线程,我已执行完成!
【分组1】,第3 号线程,我已执行完成!
【分组1】,第2 号线程,我已执行完成!
分组1比赛结束!
分组2比赛开始:
【分组2】,第1 号线程,我已经准备就绪!
【分组2】,第0 号线程,我已经准备就绪!
【分组2】,第3 号线程,我已经准备就绪!
【分组2】,第2 号线程,我已经准备就绪!
【分组2】,第4 号线程,我已经准备就绪!
分组2预备!Go!!!
【分组2】,第1 号线程,我已执行完成!
【分组2】,第0 号线程,我已执行完成!
【分组2】,第2 号线程,我已执行完成!
【分组2】,第3 号线程,我已执行完成!
【分组2】,第4 号线程,我已执行完成!
分组2比赛结束!

 
 
 
 
 
 
 
 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值