A super simple description of waiting for notifications and application scenarios between java threads

basic method

When doing some slightly complicated business, multi-threading is often used. Using multi-threading will involve thread waiting, notification and communication between threads. How do threads in java do it? Let’s start to explain

Basically use the following methods

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

Scenario 1. Threads execute sequentially

In the main thread, if there are two threads A and B, and you want to ensure that A is executed before executing B, you can use the simplest method

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

Only thread A needs to call the join() method

Scenario 2. Execute after thread notification

There are also two threads, A and B. Wait for A to finish one thing, then wait for B to finish, and then notify A after B finishes, and let A continue to work.

	创建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();

Scenario 3. Threads run synchronously, and continue execution after all threads are finished

What do you mean, the method in Scenario 1 will wait for A to be executed before executing B, and then B will start running. If there are A, B, C, D... n threads, the efficiency will be greatly reduced. How can it be Let all threads start at the same time, and wait for all threads to end before continuing. CountDownLatch is needed at this time.

		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();

Scenario 4. Threads run synchronously and ensure they start together

When there are some special needs, for example, there are three athletes A, B, and C who want to race 50 meters, then there will be a preparatory movement, or a warm-up exercise, after waiting for them to take their positions, the referee said to run, Then they just started, so how does the thread realize such a showy operation, relying on CyclicBarrier, CyclicBarrier and CountDownLatch are very similar, CountDownLatch is decreasing, and CyclicBarrier is increasing.

		创建这个等待器,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才一起开始

Scenario 5. Get thread callback results

Sometimes threads are needed to calculate something or process some tasks, but the main thread only needs to get the result and then execute it. Compared with join() in scenario 1, the difference is that the callback result can be obtained.

	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 放到线程池去管理执行

Guess you like

Origin blog.csdn.net/Janix520/article/details/124060828