23. Future: How to use multi-threading to achieve the optimal "burning water and making tea" program? -Concurrency tools

1. How to get the task execution result

ThreadPoolExecutor provides three submit () methods and a FutureTask tool class to support the need to obtain task execution results.

The signatures of the three submit () methods are as follows:

// 提交Runnable任务
Future<?> submit(Runnable task);
// 提交Callable任务
<T> Future<T> submit(Callable<T> task);
// 提交Runnable任务及结果引用  
<T> Future<T> submit(Runnable task, T result);

The above 3 methods return Future. The Future interface has 5 methods. Both get () methods are blocking. If the task is not completed when the task is called, the thread calling the get () method will block until It will be awakened after the task is executed.

// 取消任务
boolean cancel(boolean mayInterruptIfRunning);
// 判断任务是否已取消  
boolean isCancelled();
// 判断任务是否已结束
boolean isDone();
// 获得任务执行结果
get();
// 获得任务执行结果,支持超时
get(long timeout, TimeUnit unit);

The difference between these three submit () methods is that the method parameters are different,

  1. submit (Runnable task): The parameter is a Runnable interface. The run () method of the Runnable interface has no return value, so the Future returned by the submit (Runnable task) method can only be used to assert that the task has ended, similar to Thread. join ().
  2. submit (Callable task): The parameter is a Callable interface, it has only one call () method, and this method has a return value, so the Future object returned by this method can obtain the execution result of the task by calling its get () method .
  3. submit (Runnable task, T result): Assuming that the Future object returned by this method is f, the return value of f.get () is the parameter result passed to the submit () method. Note that the implementation class of the Runnable interface declares a parameterized constructor Task (Result r). When creating a Task object, a result object is passed in, so that various operations can be performed on the result in the run () method of the Task class . The result is equivalent to the bridge between the main thread and the sub-thread, through which the main sub-thread can share data.
ExecutorService executor = Executors.newFixedThreadPool(1);
// 创建Result对象r
Result r = new Result();
r.setAAA(a);
// 提交任务
Future<Result> future = executor.submit(new Task(r), r);  
Result fr = future.get();
// 下面等式成立
fr === r;
fr.getAAA() === a;
fr.getXXX() === x

class Task implements Runnable{
  Result r;
  //通过构造函数传入result
  Task(Result r){
    this.r = r;
  }
  void run() {
    //可以操作result
    a = r.getAAA();
    r.setXXX(x);
  }
}

FutureTask tool class
Two constructors:

FutureTask(Callable<V> callable);
FutureTask(Runnable runnable, V result);

FutureTask implements the Runnable and Future interfaces, which can be executed by ThreadPoolExecutor and Thread, and the execution result can be obtained.

// 创建FutureTask
FutureTask<Integer> futureTask = new FutureTask<>(()-> 1+2);
// 创建线程池
ExecutorService es = Executors.newCachedThreadPool();
// 提交FutureTask 
es.submit(futureTask);
// 获取计算结果
Integer result = futureTask.get();
// 创建FutureTask
FutureTask<Integer> futureTask = new FutureTask<>(()-> 1+2);
// 创建并启动线程
Thread T1 = new Thread(futureTask);
T1.start();
// 获取计算结果
Integer result = futureTask.get();

2. Realize the optimal "burning water and making tea" program

Insert picture description here
Two threads T1 and T2 are used to complete the boiling water and tea making process. T1 is responsible for the three processes of washing the kettle, boiling water and brewing tea. T2 is responsible for the three processes of washing the teapot, washing the tea cup and taking tea leaves. In this process, you need to wait for T2 to complete the process of taking tea.

It should be noted here that the ft1 task needs to wait for ft2 to fetch the tea leaves before executing the tea making task, so ft1 needs to reference ft2 internally, and before executing tea making, call the ft2 get () method to wait.

public class MyTest {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		// 创建任务T2的FutureTask
		FutureTask<String> ft2 = new FutureTask<>(new T2Task());
		// 创建任务T1的FutureTask
		FutureTask<String> ft1 = new FutureTask<>(new T1Task(ft2));
		// 线程T1执行任务ft1
		Thread thread1 = new Thread(ft1);
		thread1.start();
		// 线程T2执行任务ft2
		Thread thread2 = new Thread(ft2);
		thread2.start();
		// 等待线程T1执行结果
		String tea = ft1.get();
		System.out.println(tea);
	}
}
public class T1Task implements Callable<String> {
	FutureTask<String> ft2;
	public T1Task(FutureTask<String> ft2) {
		super();
		this.ft2 = ft2;
	}
	@Override
	public String call() throws Exception {
		System.out.println("T1 洗水壶---");
		TimeUnit.SECONDS.sleep(1);

		System.out.println("T1 烧开水---");
		TimeUnit.SECONDS.sleep(15);

		// 获得线程T2的茶叶
		String teaLeaf = ft2.get();
		System.out.println("T1 拿到茶叶:" + teaLeaf);

		System.out.println("T1 泡茶:" + teaLeaf);

		return "上茶:" + teaLeaf;
	}
}
public class T2Task implements Callable<String>{

	@Override
	public String call() throws Exception {
		System.out.println("T2 洗茶壶---");
		TimeUnit.SECONDS.sleep(1);
		
		System.out.println("T2 洗茶杯---");
		TimeUnit.SECONDS.sleep(2);
		
		System.out.println("T2 拿茶叶");
		TimeUnit.SECONDS.sleep(1);
		
		return "铁观音";
	}
}

Final Results
T1 Washing Kettle —
T2 Washing Teapot —
T1 Boiling Water —
T2 Washing Tea Cup —
T2 Taking Tea
T1 Getting Tea: Tieguanyin
T1 Bubble Tea: Tieguanyin
Upper Tea: Tieguanyin

Using multithreading can quickly parallelize some serial tasks to improve performance; if there are dependencies between tasks, such as the current task depends on the execution result of the previous task, this kind of problem can basically be solved with Future. In the process of analyzing this kind of problem, it is recommended that you use a directed graph to describe the dependencies between tasks, and at the same time, the division of threads is also done, similar to the picture of the optimal division of labor for boiling tea. Writing the code against the picture has the advantage of being more visual and less error-prone.

Published 97 original articles · praised 3 · 10,000+ views

Guess you like

Origin blog.csdn.net/qq_39530821/article/details/102734809