Android multithreaded programming -- thread Foundation

catalogue

1. Process and thread

What is a process?

What is a thread?

Why use multithreading?

2. Thread status

3. Create thread

4. Interruption

5. Safe thread termination

Android follows the Java thread model. An Android application will start a thread when it is created. We call it the main thread or UI thread. If we want to access the network or database and other time-consuming operations, we will start the sub thread to process, from Android 3 0, the system requires that network access must be carried out in the sub thread, otherwise an exception will be thrown; That is to avoid the main thread being blocked by time-consuming operations, resulting in ANR.

1. Process and thread

What is a process?

Process is the basis of the operating system structure, the process of the program running on a data set, and the basic unit of the system for resource allocation and scheduling. A process can be regarded as an entity of a program. At the same time, it is also a container for threads.

What is a thread?

Thread is the smallest unit of operating system scheduling, also known as lightweight process. Multiple threads can be created in a process. These threads have their own properties such as counters, stacks and local variables, and can access shared memory variables.

Why use multithreading?

At the operating system level, there are mainly the following aspects:

  • Using multithreading can reduce the response time of the program.
  • Compared with processes, the creation and switching overhead of threads is less, and multithreading is very efficient in data sharing.
  • Using multithreading can simplify the structure of the program and make the program easy to understand and maintain.

2. Thread status

Threads in the Java cycle may be in different states.

  • New new creation status. The thread has been created and the Start method has not been called. There are still some basic work to be done before the thread runs.
  • Runnable can be in running state. Once the start method is called, the thread is in the runnable state. A runnable thread may or may not be running, depending on the time the operating system provides for the thread to run.
  • Blocked blocking status. Indicates that the thread is blocked by a lock and is temporarily inactive.
  • In the Waiting state, the thread is temporarily inactive and does not run any code, which consumes the least resources until the thread scheduler reactivates it.
  • Timed waiting state. Different from the waiting state, it can return by itself at a specified time.
  • Terminated state. Indicates that the current thread has completed execution. There are two situations leading to thread termination: the first is the normal exit after the execution of the run method; The second is to terminate the run method because there is no exception caught, resulting in the thread entering the termination state.

After the thread is created, the Start method of Thread is invoked, and it starts to enter the running state. When the thread executes the wait method, the thread enters the waiting state. The thread waiting to enter the state needs other threads to notify the state. Timeout waiting is equivalent to adding a time limit to the waiting state. If the time limit is exceeded, the thread returns to the running state. When the thread calls the synchronization method, if the thread does not obtain the lock, it enters the blocking state. When the thread in the blocking state obtains the lock, it returns to the running state. When the thread finishes executing or encounters abnormal termination, it will enter the termination state.

3. Create thread

1. Inherit the Thread class and override the run method

Thrad is essentially an instance that implements the Runnable interface. It should be noted that calling the start method does not immediately execute the multithreaded code, but makes the thread Runnable. When to run the multithreaded code is determined by the operating system.

public class MyClass extends Thread{
    @Override
    public void run() {
        System.out.println("Petterp");
    }
 
    public static void main(String[] args) {
        MyClass myClass=new MyClass();
        myClass.start();
    }
}

2. Implement the Runnable interface and the run method of the interface

public class MyClass extends Thread{
    @Override
    public void run() {
        System.out.println("Petterp");
    }
 
    public static void main(String[] args) {
        MyClass myClass=new MyClass();
        myClass.start();
    }
}
  

3. Implement the Callable interface and rewrite the call method

The Callable interface belongs to the function class in the executor framework. The Callable interface has similar functions to the Runnable interface, but provides more powerful functions than Runnable.

  • Callable can provide a return value after the task is accepted. Runnable cannot provide this function.
  • The call method in Callable can throw exceptions, while the fun method of Runnable cannot throw exceptions.
  • Running Callable can get a Future object. The Future object represents the result of asynchronous calculation. It provides a method to check whether the calculation is completed. Because the thread belongs to the asynchronous computing model, it cannot get the return value of the function from other threads. In this case, you can use Future to monitor the call method called by the target thread. However, if you call the get() method of Future to get the result, the current thread will block until the call method returns the result.
class TestCallable implements Callable{
        public Object call() throws Exception {
            Thread.sleep(1000);
            return "Petterp";
        }
    }
 
 
public class MyClass {
    public static void main(String[] args) {
        TestCallable testCallable=new TestCallable();
        ExecutorService service= Executors.newCachedThreadPool();
        Future future=service.submit(testCallable);
        try {
            //Wait for the thread to end and return the result
            System.out.println(future.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }
}

4. Interruption

The thread will terminate when the run method of the thread is executed, or there is an uncapped exception in the method. In earlier versions of Java, there was a Stop method that other threads could call to terminate threads, but this method has now been deprecated. The interrupt method can be used to request an interrupt thread. When a thread calls the interrupt method, the interrupt flag bit of the thread will be set (the interrupt flag bit is true), and the thread will detect the interrupt flag bit from time to time to judge whether the thread should be interrupted. To know if the thread is set, you can call thread currentThread(). inInterrupted()

while(!Thread.currentThread().isIntterrupted()){
    
}

You can also call thread Interrupt() to reset the interrupt identification bit. However, if a thread is blocked, the interrupt state cannot be detected. If a thread is in a blocking state and the interrupt identifier is checked by the thread, if it is found that the interrupt identifier bit is true, it will throw an InterruptedException exception at the blocking method call, and reset the interrupt identifier bit of the thread, that is, reset it to false before throwing the exception. It should be noted that the interrupted thread does not necessarily terminate, Interrupting a thread is to attract the attention of the thread. The interrupted thread can decide how to respond to the interrupt. If it is an important thread, it will ignore the interrupt. In most cases, the thread will regard the interrupt as a request for termination. In addition, do not catch the InterruptedException exception in the underlying code without processing it: as shown below

class TestCallable extends Thread{
    @Override
    public  void run() {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
    }

You can handle exceptions in two ways:

  1. In the catch statement, call Thread.. currentThread. Interrupt() to set the interrupt status (because the interrupt identifier is reset after throwing an exception), so that the outside world can judge thread currentThread(). Isinterrupted() to decide whether to terminate the thread or continue.
class TestCallable extends Thread{
    @Override
    public  void run() {
                try {
                    Thread.sleep(5000);
                } catch (InterruptedException e) {
                    interrupted();
                }
            }
    }

2. A better approach is not to use try to catch such an exception and let the method throw it directly, so that the caller can catch the exception, as follows

class TestCallable extends Thread {
    @Override
    public void run() {
 
    }
    void myTask() throws InterruptedException {
        sleep(5000);
    }
}

5. Safe thread termination

class TestCallable extends Thread {
    int i=0;
    @Override
    public void run() {
        System.out.println(i++);
    }
}
 
 
 
public class MyClass {
    public static void main(String[] args) throws InterruptedException {
        final TestCallable tes=new TestCallable();
        tes.start();
        TimeUnit.MILLISECONDS.sleep(10);
        tes.interrupt();
    }
}

It can also be rewritten as follows

class TestCallable extends Thread {
    int i=0;
    private volatile  boolean on=true;
    @Override
    public void run() {
        while (on){
            System.out.println(i++);
        }
        System.out.println("stop");
    }
    public void cancel(){
        on=false;
    }
}
 
 
 
public class MyClass {
    public static void main(String[] args) throws InterruptedException {
        final TestCallable tes=new TestCallable();
        tes.start();
        TimeUnit.MILLISECONDS.sleep(100);
        tes.cancel();
    }
}
  

Added by steven21 on Wed, 09 Feb 2022 10:42:18 +0200