java 多线程 主线程等待子线程问题

reui 2016-07-15 04:40:52
场景是这样的,主线程里面创建了两个相同的thread,分别命名为A和B吧。
想实现的目的是,主线程可能在等待10秒钟,让子线程A和B去分别完成某个任务,有可能由于某个原因,A和B执行所需的时间会不同,但是我想他们两者其中一个完成之后就马上唤醒主线程(如果是A先完成了,那么主线程就不等待B),然后主线程继续去执行其他任务。如果过去10秒钟,A和B都没完成任务,那么主线程就唤醒,继续完成其他的任务
请问一下大家有什么方式可以实现呢?thx
...全文
395 15 打赏 收藏 转发到动态 举报
写回复
用AI写文章
15 条回复
切换为时间正序
请发表友善的回复…
发表回复
Mr_Sharp_007 2016-07-19
  • 打赏
  • 举报
回复
这个应该可以满足你的需求
import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

public class TestAB {

	public static void main(String[] args) {
		
		CountDownLatch countDownLatch = new CountDownLatch(1);
		ExecutorService es = Executors.newFixedThreadPool(2);
		es.submit(new Worker("A", countDownLatch));
		es.submit(new Worker("B", countDownLatch));
		es.shutdown();
		
		try {
			// 等待10秒超时
			countDownLatch.await(10, TimeUnit.SECONDS);
			if (countDownLatch.getCount() > 0) {
				System.out.println("Worker A & B do not compelete their work.");
			} else {
				System.out.println("Worker A | B has compeleted his work.");
			}
			System.out.println("Main thread done!");
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
	}
	
}

class Worker implements Runnable {

	private String name;
	private final CountDownLatch countDownLatch;
	
	public Worker(String name, CountDownLatch countDownLatch) {
		this.name = name;
		this.countDownLatch = countDownLatch;
	}
	
	@Override
	public void run() {
		
		// 模拟执行任务,随机 7 ~ 12秒
		long start = System.currentTimeMillis();
		int sleep = 7 + new Random().nextInt(5);
		try {
			Thread.sleep(sleep * 1000L);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		System.out.println(name + " has done his work!");
		System.out.println(name + " elapsed: " + (System.currentTimeMillis() - start));
		countDownLatch.countDown();
	}
	
}
ITjavaman 2016-07-18
  • 打赏
  • 举报
回复
class MyRunnable implements Runnable { private boolean b= true; @Override public void run() { // TODO Auto-generated method stub int i = 0; while (i < 10) { System.out.println(Thread.currentThread().getName() + ":" + i); i++; } if(i==10&&b){ b=false; System.out.println("---------"+Thread.currentThread().getName()+"唤醒主线程-------------"); synchronized (Test1.obj) { Test1.obj.notify(); } } } }
ITjavaman 2016-07-18
  • 打赏
  • 举报
回复
引用 11 楼 lrb0677 的回复:
[quote=引用 9 楼 ITjavaman 的回复:] 要的是不是这种
class MyRunnable implements Runnable {
	 private int i = 0;

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (i < 10) {
				System.out.println(Thread.currentThread().getName() + ":" + i);
				i++;
		}
		if(i==10){
			System.out.println("---------"+Thread.currentThread().getName()+"唤醒主线程-------------");
			synchronized (Test1.obj) {
				Test1.obj.notify();
			}
		}
	}
}

class MainThread implements Runnable {

	@Override
	public void run() {
		// TODO Auto-generated method stub
			synchronized (Test1.obj) {
				System.out.print("主线程开始运行。。。。 ");
				try {
					System.out.println("主线程被挂起10s。。。。");
					Test1.obj.wait(10*1000);
					System.out.println("主线程继续运行。。。。");
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

			}
	}

}

//测试类
public class Test1 {
	public static final Object obj = new Object();
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new Thread(new MainThread()).start();
		MyRunnable mr = new MyRunnable();
		Thread t1 = new Thread(mr, "A");
		Thread t2 = new Thread(mr, "B");
		t1.start();
		t2.start();
	}
	
}
感谢你的回复。 这种同步锁的话,貌似子线程间会依次等待,我要的效果是子线程间是相互独立不受影响,各自做自己的东西(都是一样的任务,而且是读操作),我这边的一个设计可以看一下10楼的回复。[/quote] 如果我理解的没错,你把 MyRunnable里面的i变成局部变量就能看到你要的效果- -,也就是把int i=0放到run()方法里面去
rickylin86 2016-07-18
  • 打赏
  • 举报
回复
引用 10 楼 lrb0677 的回复:
都是读操作,我的设计是这样的,主线程设置一个最长的等待时间,然后让多个子线程做一些读操作,某一子线程读完以后就放在缓存中,最后主线程去缓存内读取数据。所以我想要的一个需求应该是主线程和多个子线程之间是相互独立的,只要其中一个子线程操作完毕把数据放到缓存中,那么它就可以通知主线程去缓存取数据了,其他的子线程也不需要中断,就让它们各自做完(任务的时间不会太长,让它们做完也不会有很大的影响)
如果你的需求是这样的话那么你的设计逻辑从一开始就有问题. 应该是如下: 主线程判断缓存中是否有数据,一旦有数据那么就执行.而不是说主线程等待一个最长时间. 至于说A/B线程完成其中任务后还是中断的好.这样会节省资源,特别对于有比较多的线程通过不同方式得到相同的结果的情况下。
reui 2016-07-18
  • 打赏
  • 举报
回复
引用 9 楼 ITjavaman 的回复:
要的是不是这种
class MyRunnable implements Runnable {
	 private int i = 0;

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (i < 10) {
				System.out.println(Thread.currentThread().getName() + ":" + i);
				i++;
		}
		if(i==10){
			System.out.println("---------"+Thread.currentThread().getName()+"唤醒主线程-------------");
			synchronized (Test1.obj) {
				Test1.obj.notify();
			}
		}
	}
}

class MainThread implements Runnable {

	@Override
	public void run() {
		// TODO Auto-generated method stub
			synchronized (Test1.obj) {
				System.out.print("主线程开始运行。。。。 ");
				try {
					System.out.println("主线程被挂起10s。。。。");
					Test1.obj.wait(10*1000);
					System.out.println("主线程继续运行。。。。");
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

			}
	}

}

//测试类
public class Test1 {
	public static final Object obj = new Object();
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new Thread(new MainThread()).start();
		MyRunnable mr = new MyRunnable();
		Thread t1 = new Thread(mr, "A");
		Thread t2 = new Thread(mr, "B");
		t1.start();
		t2.start();
	}
	
}
感谢你的回复。 这种同步锁的话,貌似子线程间会依次等待,我要的效果是子线程间是相互独立不受影响,各自做自己的东西(都是一样的任务,而且是读操作),我这边的一个设计可以看一下10楼的回复。
reui 2016-07-18
  • 打赏
  • 举报
回复
引用 8 楼 rickylin86 的回复:
[quote=引用 7 楼 lrb0677 的回复:] [quote=引用 6 楼 rickylin86 的回复:] 第90行代码中.你可以把时间设置小些.比如20秒内随机,然后可以看看效果
刚测试了一下使用T = ExecutorService.invokeAny(Callable<T>)这种方式,确实能够满足到我的要求,十分感谢。 不过我有个地方比较纠结的是,对于线程的中途打断,后台会报大量各种各样的异常,包括数据库链接(执行的任务中有需要链接数据库)还有其他等等。除了这种打断其他线程的方式,能不能不打断,就让它运行,只是不管后面执行完的线程,就让它自动销毁[/quote] 那你可以把线程设置成守护线程.让main执行完毕后也跟随停止就可以了.但是除非是线程只是读操作。如果多个线程都是写操作的话那么还是存在某段时间的不确定性操作的.特别如果你的需求是满足多个写操作线程一个完成其他结束的情况下. 哪怕是用invokeAny这个方法实际上实现也是用interrupt这种方式.因为线程的stop方法由于有一定的缺陷所以java已经不建议使用了.[/quote] 都是读操作,我的设计是这样的,主线程设置一个最长的等待时间,然后让多个子线程做一些读操作,某一子线程读完以后就放在缓存中,最后主线程去缓存内读取数据。所以我想要的一个需求应该是主线程和多个子线程之间是相互独立的,只要其中一个子线程操作完毕把数据放到缓存中,那么它就可以通知主线程去缓存取数据了,其他的子线程也不需要中断,就让它们各自做完(任务的时间不会太长,让它们做完也不会有很大的影响)
ITjavaman 2016-07-18
  • 打赏
  • 举报
回复
要的是不是这种
class MyRunnable implements Runnable {
	 private int i = 0;

	@Override
	public void run() {
		// TODO Auto-generated method stub
		while (i < 10) {
				System.out.println(Thread.currentThread().getName() + ":" + i);
				i++;
		}
		if(i==10){
			System.out.println("---------"+Thread.currentThread().getName()+"唤醒主线程-------------");
			synchronized (Test1.obj) {
				Test1.obj.notify();
			}
		}
	}
}

class MainThread implements Runnable {

	@Override
	public void run() {
		// TODO Auto-generated method stub
			synchronized (Test1.obj) {
				System.out.print("主线程开始运行。。。。 ");
				try {
					System.out.println("主线程被挂起10s。。。。");
					Test1.obj.wait(10*1000);
					System.out.println("主线程继续运行。。。。");
				} catch (InterruptedException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}

			}
	}

}

//测试类
public class Test1 {
	public static final Object obj = new Object();
	public static void main(String[] args) {
		// TODO Auto-generated method stub
		new Thread(new MainThread()).start();
		MyRunnable mr = new MyRunnable();
		Thread t1 = new Thread(mr, "A");
		Thread t2 = new Thread(mr, "B");
		t1.start();
		t2.start();
	}
	
}
rickylin86 2016-07-17
  • 打赏
  • 举报
回复
引用 7 楼 lrb0677 的回复:
[quote=引用 6 楼 rickylin86 的回复:] 第90行代码中.你可以把时间设置小些.比如20秒内随机,然后可以看看效果
刚测试了一下使用T = ExecutorService.invokeAny(Callable<T>)这种方式,确实能够满足到我的要求,十分感谢。 不过我有个地方比较纠结的是,对于线程的中途打断,后台会报大量各种各样的异常,包括数据库链接(执行的任务中有需要链接数据库)还有其他等等。除了这种打断其他线程的方式,能不能不打断,就让它运行,只是不管后面执行完的线程,就让它自动销毁[/quote] 那你可以把线程设置成守护线程.让main执行完毕后也跟随停止就可以了.但是除非是线程只是读操作。如果多个线程都是写操作的话那么还是存在某段时间的不确定性操作的.特别如果你的需求是满足多个写操作线程一个完成其他结束的情况下. 哪怕是用invokeAny这个方法实际上实现也是用interrupt这种方式.因为线程的stop方法由于有一定的缺陷所以java已经不建议使用了.
reui 2016-07-17
  • 打赏
  • 举报
回复
引用 6 楼 rickylin86 的回复:
第90行代码中.你可以把时间设置小些.比如20秒内随机,然后可以看看效果
刚测试了一下使用T = ExecutorService.invokeAny(Callable<T>)这种方式,确实能够满足到我的要求,十分感谢。 不过我有个地方比较纠结的是,对于线程的中途打断,后台会报大量各种各样的异常,包括数据库链接(执行的任务中有需要链接数据库)还有其他等等。除了这种打断其他线程的方式,能不能不打断,就让它运行,只是不管后面执行完的线程,就让它自动销毁
rickylin86 2016-07-16
  • 打赏
  • 举报
回复

import java.util.concurrent.Future;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.List;
import java.util.ArrayList;

public class Test{
	public static void main(String[] args){

		Task A = new Task("A");
		Task B = new Task("B");

		Object o = new Object();

		Server server = new Server(o,A,B);
		Thread serverThread = new Thread(server);
		serverThread.start();

		synchronized(o){
			try{
				o.wait(10000);//线程等待10秒
				serverThread.interrupt();//中断线程
			}catch(InterruptedException e){
				e.printStackTrace();
				System.exit(1);
			}
		}

		System.out.println("Main: finished!");
	}
}

class Task implements Callable<String>{

	public Task(String name){
		this.name = name;
	}

	@Override
	public String call()throws Exception{
		long duration = (long)(Math.random() * 20);//设置随机等待时间.
		System.out.printf("%s: Waiting %d seconds for processing!\n",name,duration);
		try{
			TimeUnit.SECONDS.sleep(duration);
		}catch(InterruptedException e){
			return null;
		}
		System.out.printf("%s: Finished!\n",name);
		
		return name;
	}

	private String name;
}

class Server implements Runnable{
	
	public Server(Object o,Task ... tasks){
		this.o = o;
		for(Task task : tasks){
			taskList.add(task);
		}
	}


	@Override
	public void run(){
		try{
			executor.invokeAny(taskList);
		}catch(InterruptedException|ExecutionException e){
			
		}finally{
			executor.shutdown();
		}

		synchronized(o){
			o.notifyAll();
		}
	}


	private ExecutorService executor = Executors.newCachedThreadPool();
	private List<Task> taskList = new ArrayList<>();
	private final Object o;
}
rickylin86 2016-07-16
  • 打赏
  • 举报
回复
第90行代码中.你可以把时间设置小些.比如20秒内随机,然后可以看看效果
rickylin86 2016-07-16
  • 打赏
  • 举报
回复
我前面发的代码用执行器框架实现你要需求.T = ExecutorService.invokeAny(Callable<T>)这个方法正好可以实现,以后你如果有学到这个包的时候可以回头看看你现在提出来的这个需求. 如果不要用多线程工具包的话可以考虑用下面的实现逻辑代码.

public class Test{
	
	public static void main(String[] args){
		Task task = new Task("A");
		MyThread threadA = new MyThread(task,"A");
		MyThread threadB = new MyThread(task,"B");
		threadA.start();
		threadB.start();
		Object synObject = new Object();
		ConditionThread condition = new ConditionThread(synObject,threadA,threadB);
		condition.start();//监控线程

		synchronized(synObject){
			try{
				synObject.wait(10000);//主线程等待10秒
			}catch(InterruptedException e){
				
			}
			//10秒后中断线程A和线程B
			threadA.interrupt();
			threadB.interrupt();
			
		}
	}
}

class ConditionThread extends Thread{
	//这个线程是监控线程.一旦发现传入的线程中有某个已经优先完成.那么将中断剩余的线程.
	public ConditionThread(Object synObject,MyThread ... threads){
		this.threads = threads;
		this.synObject = synObject;
	}

	@Override
	public void run(){
		while(true){
			for(int i = 0 ; i < threads.length ; i ++){
				if(threads[i].getCondition()){
					
					for(int j = 0 ; j < i ; j ++ ){
						threads[j].interrupt();
					}
					for(int j = i + 1 ; j < threads.length ; j ++){
						threads[j].interrupt();
					}
					synchronized(synObject){
						synObject.notifyAll();
					}
					return;
				}
			}
		}
	}

	private MyThread[] threads;
	private Object synObject;
}


class MyThread extends Thread{
	public MyThread(Runnable task,String name){
		super(task,name);
	}

	@Override
	public void run(){
		super.run();
		condition = true;
	}

	public boolean getCondition(){
		//判断改线程是否已经完成.
		return condition;
	}

	private boolean condition = false;
}


class Task implements Runnable{
	
	public Task(String str){
		this.str = str;
	}

	@Override
	public void run(){
		long duration = (long)(Math.random() * 50);//注:这里可以时间长些,一旦线程需要的均时间超过10秒,那么main线程等待10秒后将中断该线程
		System.out.printf("%s: waiting %d seconds for processing.\n",Thread.currentThread().getName(),duration);
		try{
			Thread.sleep(duration * 1000);
		}catch(InterruptedException e){
			return;
		}
		System.out.printf("%s: finish!\n",Thread.currentThread().getName());
	}


	private String str;
}
reui 2016-07-16
  • 打赏
  • 举报
回复
引用 3 楼 rickylin86 的回复:

import java.util.concurrent.Future;
import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Callable;
import java.util.concurrent.TimeUnit;
import java.util.List;
import java.util.ArrayList;

public class Test{
	public static void main(String[] args){

		Task A = new Task("A");
		Task B = new Task("B");

		Object o = new Object();

		Server server = new Server(o,A,B);
		Thread serverThread = new Thread(server);
		serverThread.start();

		synchronized(o){
			try{
				o.wait(10000);//线程等待10秒
				serverThread.interrupt();//中断线程
			}catch(InterruptedException e){
				e.printStackTrace();
				System.exit(1);
			}
		}

		System.out.println("Main: finished!");
	}
}

class Task implements Callable<String>{

	public Task(String name){
		this.name = name;
	}

	@Override
	public String call()throws Exception{
		long duration = (long)(Math.random() * 20);//设置随机等待时间.
		System.out.printf("%s: Waiting %d seconds for processing!\n",name,duration);
		try{
			TimeUnit.SECONDS.sleep(duration);
		}catch(InterruptedException e){
			return null;
		}
		System.out.printf("%s: Finished!\n",name);
		
		return name;
	}

	private String name;
}

class Server implements Runnable{
	
	public Server(Object o,Task ... tasks){
		this.o = o;
		for(Task task : tasks){
			taskList.add(task);
		}
	}


	@Override
	public void run(){
		try{
			executor.invokeAny(taskList);
		}catch(InterruptedException|ExecutionException e){
			
		}finally{
			executor.shutdown();
		}

		synchronized(o){
			o.notifyAll();
		}
	}


	private ExecutorService executor = Executors.newCachedThreadPool();
	private List<Task> taskList = new ArrayList<>();
	private final Object o;
}
感谢你的回复。 我这边的情况应该是

.....
Task A = new Task("A");//相同的任务
Thread a = new Thread(A);//两条不同的子线程去完成一个相同的任务
Thread b = new Thread(A);
a.start();
b.start();
想达到的效果是,a或b谁先完成了就谁去唤醒主线程,主线程不再等待。 有一种方式貌似是可以使用共享对象的方式实现,但是具体不知道要怎么做。
reui 2016-07-15
  • 打赏
  • 举报
回复
引用 1 楼 bichir 的回复:
带参的wait与notify实现
能不能具体一点是怎么个带参?
bichir 2016-07-15
  • 打赏
  • 举报
回复
带参的wait与notify实现

50,530

社区成员

发帖
与我相关
我的任务
社区描述
Java相关技术讨论
javaspring bootspring cloud 技术论坛(原bbs)
社区管理员
  • Java相关社区
  • 小虚竹
  • 谙忆
加入社区
  • 近7日
  • 近30日
  • 至今
社区公告
暂无公告

试试用AI创作助手写篇文章吧