java线程之间等待通知及应用场景的超简单描述

基本方法

在做一些稍微复杂的业务时,常常会用到多线程,使用多线程就会涉及到线程的等待、通知以及线程之间的通信,java中的线程怎么做到呢,下面开始讲解

基本用到以下这些方法

thread.join(),
object.wait(),
object.notify(),
CountdownLatch,
CyclicBarrier,
FutureTask,
Callable

场景1、线程依次执行

在主线程中,假如有两个线程 A、B,想要确保让A执行完,再执行B,那就可以使用最简单的方法

		threadA.start();
		threadA.join();
		threadB.start();

只需要线程A调用join()方法

场景2、线程通知后再执行

同样有A、B两个线程,等A干完了一件事,再等B干完,B干完再通知A,让A继续干。

	创建Object作为公共锁
	Object lock = new Object();
	Thread A = new Thread(new Runnable() {
			@Override
			public void run() {
				synchronized (lock) {
					System.out.println("A的第一件事 执行完了");
					try {
						lock.wait();
					} catch (InterruptedException e) {
						e.printStackTrace();
					}
					System.out.println("A的第二件事");
				}
			}
		});
		Thread B = new Thread(new Runnable() {
			@Override
			public void run() {
				synchronized (lock) {
					System.out.println("B:我开始干了");
					lock.notify();	//执行notify,线程A就重新拾取锁钥匙,继续干
				}
			}
		});
		A.start();
		B.start();

场景3、线程同步运行,全部结束再继续执行

啥意思呢,场景1中方法,会等待A执行完,再执行B,那B才开始运行,那要是有A、B、C、D……n个线程,这样效率不就大大降低,怎么才能让所有线程同时开始,并等所有线程结束后再继续,这时需要CountDownLatch。

		int worker = 2; 假如总共就2个线程AB
		CountDownLatch countDownLatch = new CountDownLatch(worker);
		new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println("我在等其他线程全部干完");
				try {
					countDownLatch.await();
					System.out.println("其他都结束了, 我开始干了");
				} catch (InterruptedException e) {
					e.printStackTrace();
				}
			}
		}).start();
	//线程
	Thread A = new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println("A:我干完了");
				countDownLatch.countDown();
			}
		});
		Thread B = new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println("B:我也干完了");
				countDownLatch.countDown(); 
				
				countDownLatch相当于是个倒计数器,本身worker是2,当A调用countDown(); 就剩1
				B又调用一次,线程没完成的已经为0了,此时await()地方就重新开始
			}
		});
		A.start();
		B.start();

场景4、线程同步运行,并确保是一起开始的

当有一些特殊需求,举个例子,有A、B、C三个运动员,他们要比赛50米,那么会有个预备动作,或者说是预热运动,等待他们各就各位之后,裁判员说跑,那么他们才开始,那么线程是如何实现这样的骚操作,靠CyclicBarrier,CyclicBarrier和CountDownLatch很像,CountDownLatch是递减,CyclicBarrier则是递增。

		创建这个等待器,worker依然是2
		CyclicBarrier cyclicBarrier = new CyclicBarrier(2);
		Thread A = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					Thread.sleep(5000);
					cyclicBarrier.await();

					System.out.println("A");
				} catch (Exception e1) {
				}

			}
		});
		Thread B = new Thread(new Runnable() {
			@Override
			public void run() {
				try {
					cyclicBarrier.await();
				} catch (InterruptedException e) {
				} catch (BrokenBarrierException e) {
				}
				System.out.println("B");
			}
		});
		
		A.start();
		B.start();
	
	此时的A需要5秒钟准备,而B不会开始,会等A调用await()之后,AB才一起开始

场景5、获取线程回调结果

有时候需要线程去算一些东西,或者处理一些任务,而主线程中只需要拿到结果,再往下执行,相对于场景1中join(),不同的是能获取到回调结果。

	1、创建任务处理方法
	Callable<Integer> callable = new Callable<Integer>() {
			@Override
			public Integer call() throws Exception {
				System.out.println("任务开始");
				int result = 100;
				return result;
			}
		};
		
		2、新建这个么回调任务
		FutureTask<Integer> futureTask = new FutureTask<>(callable);
		new Thread(futureTask).start();
		try {
			System.out.println("执行任务前");
			System.out.println("执行结果:" + futureTask.get());
			System.out.println("获取结果后");
		} catch (Exception e) {
			e.printStackTrace();
		} 
		
此时调用的get()方法会阻塞主线程,然后 Callable 内部开始执行,并返回运算结果,
得到结果后主线程继续执行。
当然,如果你不希望阻塞主线程,可以考虑利使用用线程池之类的东西,比如ExecutorService,
把FutureTask 放到线程池去管理执行
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值