Application scenarios of Callable, Future and FutureTask in multithreading

Posted by fitzbean on Sun, 20 Feb 2022 04:58:31 +0100

1.1Callable and Future and FutureTask creation process

Many times, we ask multithreading to help us deal with things. We need to get the return value, and we can deal with exceptions

Note that callable can have a return value or throw an exception, which is key.

1.1.2.callable implements multithreading by itself, but there is no return value

package com.Li.Callables;
import java.util.concurrent.Callable;
/**
 * @Description: Callable Implementation class of interface
 * @auther:Li Ya Hui
 * @Time:2021 April 22, 2007 7:18:09 PM
 */
public class Callableimpl implements Callable<Integer> {
	@Override
	public Integer call() throws Exception {
		System.out.println("Name of current thread:"+Thread.currentThread().getName());
		return null;
	}
}

package com.Li.Callables
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
/**
 * @Description:	
 * @auther:Li Ya Hui
 * @Time:2021 April 23, 2014 4:02:41 PM
 */
public class Test {
	public static void main(String[] args) {
		//1. Create a single thread pool
		ExecutorService single = Executors.newSingleThreadExecutor();
		//2. Instantiation of implementation class of callable interface
		Callableimpl callableimpl = new Callableimpl();
		//3. Add the newly created thread to the thread pool
		single.submit(callableimpl);
	}
}

1.1.2 realize multi line and obtain results through label + future

package com.Li.Callables;
import java.util.concurrent.Callable;
/**
 * @Description: Callable Implementation class of interface
 * @auther:Li Ya Hui
 * @Time:2021 April 22, 2007 7:18:09 PM
 */
public class Callableimpl implements Callable<Integer> {
	//Define a variable to accept the result of thread task execution
	public int sum = 0;
	@Override
	//Rewrite the callable interface method
	public Integer call() throws Exception {
		System.out.println("Name of current thread:"+Thread.currentThread().getName());
		System.out.println("Through implementation callable The multithreading of interface creation begins to execute");
		//Simulate a time-consuming feeling
		Thread.sleep(1000);
		for (int i = 0; i < 100; i++) {
			sum+=i;
		}
		System.out.println("Through implementation callable The multithreading of interface creation ends");
		return null;
	}
}

package com.Li.Callables;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
 * @Description:	The test realizes multithreading and obtains results through callable+future
 * @auther:Li Ya Hui
 * @Time:2021 April 23, 2014 4:02:41 PM
 */
public class Test {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		//1. Create a single thread pool
		ExecutorService single = Executors.newSingleThreadExecutor();
//		ExecutorService single = Executors.newFixedThreadPool(5);
//		ExecutorService single = Executors.newSingleThreadExecutor();
//		ExecutorService single = Executors.newScheduledThreadPool(1);
		
		//2. Instantiation of implementation class of callable interface
		Callableimpl callableimpl = new Callableimpl();
		
		//3. Add the newly created thread to the thread pool
		//single.submit(callableimpl);
		Future<Integer> future = single.submit(callableimpl);
		
		//4. Close thread pool
		single.shutdown();
		if(single.isShutdown()) 
		{			
			System.out.println("Thread pool closed");
		}
		//The simulated main function still exists
		Thread.sleep(3000);
		System.out.println("The main function thread still exists");
		
		//5. Take out the result after the execution of the new thread 
		if ((future.get())!=null)
		{			
			System.out.println(future.get()); 
		}else 
		{
			System.out.println("future.get()The result obtained is null");
		}
		if(future.isDone()) 
		{
			System.out.println("The task in the thread pool has been completed!");
		}
		System.out.println("The main function thread has ended");
	}
}

1.1.3 realize multithreading through label + future, and obtain results and throw exceptions

package com.Li.Callables;

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;

/**
 * @Description:  callable The implementation class callable+future implements multithreading, and obtains results and throws exceptions
 * @auther:Li Ya Hui
 * @Time:2021 April 23, 2008 8:21:58 PM
 */ 
public class Callable02  implements Callable<String>{
	//Define a variable to represent ready-made different uses
	public int flag;
	//Construction method pass flag
	public Callable02(int a ) {
		super();
		this.flag =  a;
	}
	@Override
	public String call() throws Exception {
		//The first of the three operation tasks is normal
		if (flag == 0) 
		{
			return "flag == 0";
		}
		//Three kinds of running tasks, the second kind of dead cycle
		if (flag == 1 ) 
		{
			try {
				while (true) {
					System.out.println("Dead cycle.....");
					Thread.sleep(2000);
				}
			} catch (InterruptedException e) {
				System.out.println("Interrupt exception");
			}
			return "false ";
		}
		//There are three kinds of running tasks, and the third one will report an error
		else 
		{
			throw new Exception("Incorrect input");
		}
	}
}

package com.Li.Callables;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
/**
 * @Description:  Test class, test callable+future, realize multithreading and obtain results, and throw exceptions
 * @auther:Li Ya Hui
 * @Time:2021 9:18:47 PM, April 23
 */
public class Test02 {
	public static void main(String[] args) throws InterruptedException, ExecutionException {
		//1. Create three new threads
		Callable02 task1= new Callable02(0);
		Callable02 task2 = new Callable02(1);
		Callable02 task3 = new Callable02(2);
		//2. Create thread pool
		ExecutorService fixedThreadPool = Executors.newFixedThreadPool(3);
		//3. Load the three threads into the thread pool one by one
		Future<String> future = fixedThreadPool.submit(task1);
		System.out.println(future.get());
		Future<String> future2 = fixedThreadPool.submit(task2);
//		System.out.println(future2.get());//  The return value cannot be obtained because it will cause the thread to be blocked waiting for the result
		//Assume that task 2 ends in 5 seconds
		Thread.sleep(5000);
		future2.cancel(true);//Directly cancel the normal execution of thread task (TRUE)
		System.out.println(future2);
		//If an error is reported, catch
		try {
			Future<String> future3 = fixedThreadPool.submit(task3);
			System.out.println(future3.get());
		} catch (Exception e) {
			System.out.println(e.getMessage());
		}
		//Close thread pool
		fixedThreadPool.shutdown();
	}

}

1.1.4 realize multithreading and obtain results through label + future

package com.Li.Callables;
import java.util.concurrent.Callable;
/**
 * @Description: Callable Implementation class of interface
 * @auther:Li Ya Hui
 * @Time:2021 April 22, 2007 7:18:09 PM
 */
public class Callable03 implements Callable<Integer> {
	//Define a variable to accept the result of thread task execution
	public int sum = 0;
	@Override
	//Rewrite the callable interface method
	public Integer call() throws Exception {
		System.out.println("Name of current thread:"+Thread.currentThread().getName());
		System.out.println("Through implementation callable The multithreading of interface creation begins to execute");
		//Simulate a time-consuming feeling
		Thread.sleep(1000);
		for (int i = 0; i < 100; i++) {
			sum+=i;
		}
		System.out.println("Through implementation callable The multithreading of interface creation ends");
		return sum;
	}
}

package com.Li.Callables;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
/**
 * @Description:	The test realizes multithreading and obtains results through callable+future
 * @auther:Li Ya Hui
 * @Time:2021 April 23, 2014 4:02:41 PM
   */
   public class Test3 {
   public static void main(String[] args) throws InterruptedException, ExecutionException {
   	//1. Create a single thread pool
   	ExecutorService single = Executors.newSingleThreadExecutor();
   	//2. Instantiation of call interface implementation class
   	Callable03 callable03 = new Callable03();
   	//Pass the implementation object of the call able interface into the constructor of Future Task to obtain the instantiation object of Future Task
   	FutureTask<Integer> futureTask = new FutureTask<Integer>(callable03);
   	//4. Add the instantiated object of Future Task to the thread pool and execute it
   	single.submit(futureTask);
   	//5. Close thread pool
   	single.shutdown();

   //Simulate that the main function thread still has words
   Thread.sleep(3000);
   System.out.println("The main function thread still exists");
   if ((futureTask.get())!=null) 
   {
   	System.out.println(futureTask.get());
   }else 
   {
   	System.out.println("The new results are:"+futureTask.get());
   }
   //6. Obtain the results after thread execution through Future task
   System.out.println("The main function thread has ended");
   }
}

2.1. Introduction to future

The Future interface is used to obtain the results of asynchronous calculation. You can obtain the results through get(), cancel() and isDone() to determine whether it is completed.

  • V get(): get the result. If there is no result, it will block until the asynchronous calculation is completed
  • V get(long timeOut, TimeUnit unit): get the result and return null when timeout
  • boolean isDone(): return true at the end of execution (completion / cancellation / exception)
  • boolean isCancelled(): true if the task is cancelled before completion
  • boolean cancel(boolean mayInterruptRunning): cancels a task, returns false if it has not started or completed. The parameter indicates whether to interrupt the executing thread

2.1 false parameter in cancel()

As described above, passing in true will interrupt the thread to stop the task, and passing in false will make the thread execute normally until it is completed. At first, I can't understand the role of passing in false. Since the thread will not be interrupted, isn't this cancel method meaningless? Later, I consulted many materials in stackoverflow I found a better explanation and finally realized it.

Simply put, passing in the false parameter can only cancel the task that has not started. If the task has started, it will be allowed to run.

When a Future instance is created, the task may have the following three states:

  • Wait state. At this time, calling the cancel() method will be marked as cancelled no matter whether true or false is passed in, and the task will still be saved in the task queue, but will be skipped directly when this task runs.
  • Completion status. cancel() doesn't work at this point, because the task is complete.
  • Running. At this time, passing in true will interrupt the task being executed, and passing in false will not interrupt.

3.1. In a word, understand the difference between shutdown and shutdown now

  • Shutdown only sets the state of the thread pool to the shutdown state. The executing tasks will continue to be executed, and those not executed will be interrupted.
  • Shutdown now sets the status of the thread pool to STOP, and the executing task is stopped, and the non executing task is returned.

Take an example of workers eating steamed stuffed buns. Workers in a factory are eating steamed stuffed buns (which can be understood as a task). If they receive the shutdown order, the workers in the factory will eat the steamed stuffed buns they have on hand, and the steamed stuffed buns in the cage they don't get in hand can't be eaten! And if these workers immediately stop eating steamed stuffed buns after receiving the shutdown now order, they will put down the unfinished steamed stuffed buns on hand, let alone the steamed stuffed buns in the cage.

3.2 thread pool process:

​ 1. When a thread pool is created, the thread pool is in the RUNNING state at the beginning, and the tasks in the thread pool are 0;

2. If the shutdown() method is called, the thread pool is in the SHUTDOWN state. At this time, the thread pool cannot accept new tasks, and it will wait for all tasks to be executed;

3. If the shutdown now () method is called, the thread pool is in the STOP state. At this time, the thread pool cannot accept new tasks and will try to terminate the executing tasks;

​ 4. When all tasks have been terminated, the "number of tasks" recorded by ctl is 0, and the thread pool will change to TIDYING state. The terminated() function is then executed.

5. When the thread pool is in the TIDYING state, after executing terminated(), the thread pool will be set to the TERMINATED state by TIDYING - > TERMINATED

4.cancel summary

Future.cancel(true) applies to:

  1. Tasks that have been running for a long time and can handle interruption

Future.cancel(false) applies to:

  1. Failed to process task for interruption
  2. It is unclear whether the task supports cancellation
  3. You need to wait for the task that has been started to complete

Topics: Java Multithreading future