Copyright notice: this article is the blogger’s original article, without the permission of the blogger shall not be reproduced source: github.com/AnliaLee if you see any mistakes or good suggestions, welcome to leave a comment

preface

In Android Multithreading (part 1), we talked about two ways to create threads (inheriting threads and implementing the Runnable interface) and compared the differences. In this chapter we’ll look at the third way — creating threads by implementing the Callable interface

A synchronized Handler is used to parse the communication mechanism between Android threads and Runnable threads


Implement the Callable interface to create threads

Let’s take a quick look at how threads are created by implementing the Callable interface

One day, in front of the high-speed railway station, old C said goodbye to his son. The son said, “Dad, you can go now.” Old C looked at the roadside stalls, said

Then C went to the stand to buy oranges.

public static class TestCallable implements Callable{
	@Override
	public String call(a) throws Exception {
		System.out.println(Thread.currentThread().getName() + "I'll buy some oranges. You stay right here. Don't move." + "Time:" + getTime());
		Thread.sleep(2000);// Simulate the time to buy oranges
		return Thread.currentThread().getName() + "I came back from buying oranges." + "Time:"+ getTime(); }}Copy the code

Naturally, the son stood obediently waiting for his father to buy oranges

public class CallableTest {
    // omit some code...
    public static void main(String args[]){
        TestCallable callable = new TestCallable();
        FutureTask<String> futureTask = new FutureTask<String>(callable);
		
        Thread thread1 = new Thread(futureTask, "Dad");
        thread1.start();

        System.out.println("Son hasn't received an orange yet." + "Time:" + getTime());// Verify the execution of the main thread
        try{
            System.out.println(futureTask.get());
            System.out.println("Son receives orange" + "Time:" + getTime());// Verify the execution of the main thread
        }catch (InterruptedException | ExecutionException e){
        }
    }
}
Copy the code

The normal buy orange run results are as follows

What if we don’t get an orange (we try to throw an exception in the call() method and catch it when the get() method is called)?

public static class TestCallable implements Callable{
	private int ticket = 10;

	@Override
	public String call(a) throws Exception {
		System.out.println(Thread.currentThread().getName() + "I'll buy some oranges. You stay right here. Don't move." + "Time:" + getTime());
		Thread.sleep(2000);// Simulate the time to buy oranges
		System.out.println(Thread.currentThread().getName() + Oranges are sold out. + "Time:" + getTime());
		
		throw new NullPointerException("Oranges are sold out."); }}public static void main(String args[]){
	TestCallable callable = new TestCallable();
	FutureTask<String> futureTask = new FutureTask<String>(callable);

	Thread thread1 = new Thread(futureTask, "Dad");
	thread1.start();

	System.out.println("The son stood where he was." + "Time:" + getTime());// Verify the execution of the main thread
	try{
		System.out.println(futureTask.get());
		System.out.println("Son receives orange" + "Time:" + getTime());// Verify the execution of the main thread
	}catch (InterruptedException | ExecutionException e){
		System.out.println("Son didn't get an orange." + "Time:" + getTime());// Verify the execution of the main thread}}Copy the code

Also note that Dad only has enough money to buy a bag of oranges (the mission can only be performed once)

public static void main(String args[]){
	TestCallable callable = new TestCallable();
	FutureTask<String> futureTask = new FutureTask<String>(callable);

	Thread thread1 = new Thread(futureTask, "Dad went to the first stall.");
	Thread thread2 = new Thread(futureTask, "Dad went to the second booth.");
	Thread thread3 = new Thread(futureTask, "Dad went to the third booth.");

	thread1.start();
	thread2.start();
	thread3.start();

	System.out.println("The son stood where he was." + "Time:" + getTime());// Verify the execution of the main thread
	try{
		System.out.println(futureTask.get());
		System.out.println("Son receives orange" + "Time:" + getTime());// Verify the execution of the main thread
	}catch (InterruptedException | ExecutionException e){
		System.out.println("Son didn't get an orange." + "Time:" + getTime());// Verify the execution of the main thread}}Copy the code

To summarize the above cases:

  • After the Callable is executed by the thread, it can provide a return value, which we can retrieve through the Future’s get() method

Future is an interface, and FutureTask implements the RunnableFuture interface. RunnableFuture inherits both the Runnable interface and the Future interface (see figure below).

FutureTask is used to asynchronously obtain execution results or cancel tasks. Its main functions are as follows:

  • You can determine if the task is complete
  • You can obtain the task execution result
  • Can interrupt the task

Java Concurrent Programming: Callable, Future and FutureTask Analysis Java FutureTask source code analysis on Android implementation FutureTask usage and two common usage scenarios

  • Callable’s call() method can throw an exception that we can catch when we try to execute the get() method

Unlike the way the Runnable interface creates threads, Runnable does not implement these two functions

  • FutureTask ensures that the task is executed only once
  • When we execute get() on a thread, the thread will block until the Future gets the return value from callable.call ()

Use this in UI threads (especially when updating the UI later) to avoid interface lag. So how do you handle a situation where multiple threads execute time-consuming tasks, wait for results, and then update the UI? That’s right! The AsyncTask provided by The Android system implements asynchronous operations in this way by using the Handler described in the previous chapter. We will introduce AsyncTask in detail in the following chapters

Additionally, in addition to directly new a Thread, we can use Thread pools to perform multithreaded tasks in conjunction with Callable

public static void main(String args[]){
	TestCallable callable = new TestCallable();
	ExecutorService executor = Executors.newCachedThreadPool();
	Future<String> future = executor.submit(callable);
	
	/ / or
	//FutureTask<String> future = new FutureTask<String>(callable);
	//executor.execute(future);
	System.out.println("The son stood where he was." + "Time:" + getTime());// Verify the execution of the main thread
	try{
		System.out.println(future.get());
		System.out.println("Son receives orange" + "Time:" + getTime());// Verify the execution of the main thread
	}catch (InterruptedException | ExecutionException e){
		System.out.println("Son didn't get an orange." + "Time:" + getTime());// Verify the execution of the main thread}}Copy the code

What about thread pools? Save that for the big talk in the next chapter

This is the end of this blog, if you have any questions or suggestions please leave a comment, thank you very much. Please give me a thumbs up if you think it’s good, your support is my biggest motivation ~