Multithread, it's so simple!

Keywords: Java jvm github

This article belongs to xxKarina Original, reproduced please note
Personal blog address: https://xxkarina.github.io/

Essentials

  • What is a thread?
  • What are threads?
  • How to Use Threads

What are threads?

To learn threads, we first need to understand several common concepts:

  • process Every program running on the system is a process. A process contains at least one thread. The process can be dynamic execution of whole or part of the program.
    • thread Threads are a set of instructions, a lightweight process, and an execution unit responsible for program execution in the process. Threads rely on programs and are the sequential control flow in programs, requiring the use of program resources and environment.
    • Multithreading A simple understanding is that running multiple tasks in a program is to make better use of CPU resources, speed up the process, increase efficiency, and achieve concurrent execution of multiple threads.

With multithreading, we can achieve concurrency

  • Concurrent Through CPU scheduling algorithm to achieve macro-level parallel Microscopically serial technology

What are threads?

Thread status:

As we all know, threads also have declaration cycles, and the whole declaration cycle has five basic states:

  • New state: Create a new thread object
  • Ready state: After an object is created, if the thread executes the start() method, it will be in the thread pool, waiting for CPU usage, which is a runnable state.
  • Running state: On the basis of ready state, the CPU usage right is obtained, and then the program code is executed, in the running state.
  • Blocking state: Threads lose CPU usage for some reason, temporarily stop running and turn to blocking state. To run again, they must go through the first to ready state. There are three common blocking situations:

    • Wait blocking: A running thread that executes the wait() method is put into the waiting pool by the JVM
    • Synchronization blocking: Running threads are also put into the waiting pool by the JVM when the synchronization lock of the acquisition object fails.
    • Other blockages: If a running thread executes a sleep() or join() method, or makes an I/O request, the thread pauses and enters a blocking state.
  • Death status:

I borrowed a picture I found online to describe the relationship between them.

How do threads work?

Here, let's elaborate on why.

  • Method 1 for creating threads: inherit the Thread class

Thread class is a thread class, which essentially implements the Runnable interface. An instance of this class is a thread. The task that a thread wants to perform is written in the run() method in the form of:

public abstract void run ()

The commonly used methods of the Thread class are:

  • //Thread threads, usually Thread Overlay in Subclasses of Classes
  • public void run()
  • //from JVM Calling threads run()Method, start the thread and start execution
  • public void start()
  • //Returns the thread object reference being executed
  • public static Thread currentThread()
  • //Set the thread name
  • public void setName(String name)
  • //Returns the thread name
  • public void getName()
  • //To temporarily stop execution of a specified millisecond time by the currently executing thread, exceptions need to be handled
  • public static void sleep(long millis)
  • //To suspend execution of currently executing threads and allow other threads to execute
  • public static void yield()
  • //Interrupt the current thread
  • public void interrupt()
  • //Returns whether the specified thread is active
  • public boolean isAlive()

Create a thread Demo (inherit Thread):

/*
 * Enter the threaded program to view the results
 */
class SimpleThread extends Thread {
    public SimpleThread(String str) {
        super(str); // Call the construction method of its parent class
    }

    public void run() { // Rewriting run Method
        for (int i = 0; i < 10; i++) {
            System.out.println(i + " " + getName());
            // Print times and thread names
            try {
                sleep((int) (Math.random() * 1000));
                // Thread Sleep, Hand Over Control
            } catch (InterruptedException e) {
            }
        }
        System.out.println("DONE! " + getName());
        // Thread code is done.
    }

}

public class TwoThreadsTest {
    public static void main(String args[]) {
        new SimpleThread("First").start();
        // The name of the first thread is First
        new SimpleThread("Second").start();
        // The name of the second thread is Second
    }

}

First, the SimpleThread class inherits the Thread class, and then adds the code to be executed in the run() method (thread body) it covers. Then, through the new method, two different threads are created and their start() method is executed to start execution.

Executing the above code several times, you will find that each execution results are different, which further illustrates the independence of multi-threading and achieves the goal of asynchrony.

  • Creating Thread Method 2: Implementing Runnable Interface

Inheritance of Thread classes is better understood, but based on the fact that Java does not support multi-inheritance, this brings us further trouble. In this case, we can use the second way to implement the Runnable interface. As we mentioned above, the essence of inheriting Thread classes is to implement the Runnable interface, so their use methods are very similar, almost the same.

Create a threaded Demo (to implement the Runnable interface):

/*
 * Enter the threaded program to view the results
 */
class SimpleThread implements Runnable {
    public SimpleThread() {
        super(); // Call the construction method of its parent class
    }

    public void run() { // Rewriting run Method
        for (int i = 0; i < 10; i++) {
            System.out.println(i + " " + Thread.currentThread().getName());
            // Print times and thread names
            try {
                Thread.sleep((int) (Math.random() * 1000));
                // Thread Sleep, Hand Over Control
            } catch (InterruptedException e) {
            }
        }
        System.out.println("DONE! " + Thread.currentThread().getName());
        // Thread code is done.
    }

}

public class TwoThreadsTest {
    public static void main(String args[]) {
        SimpleThread target = new SimpleThread();
        new Thread(target,"First").start();
        // The name of the first thread is First
        new Thread(target,"Second").start();
        // The name of the second thread is Second
    }

}

Since we do not inherit the Thread class, we need to base our operations on the Thread class when calling methods or creating threads.

  • Creating Thread Method 3: Implementing Callable Interface

Using Callable and Future interfaces to create threads is to create the implementation class of Callable interface and implement the call() method. The FutureTask class is used to wrap the object of Callable implementation class, and the FutureTask object is used as the target of Thread object to create threads.

Create a thread Demo (to implement the Callable interface):

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

class SimpleThread implements Callable<Integer> {
    public Integer call() throws Exception {
        int sum = 0;
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
            sum += i;
        }

        return sum;
    }
}

public class TwoThreadsTest {
    public static void main(String args[]) {
        // create object
        Callable<Integer> simpleThread = new SimpleThread();
        // Use FutureTask to wrap objects
        FutureTask<Integer> ft = new FutureTask<Integer>(simpleThread);
        for (int i = 0; i < 10; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
            // FutureTask object creates new threads as target of Thread object
            Thread thread = new Thread(ft);
            thread.start();
            // Thread code is done.
            System.out.println("DONE! ");
            try {
                // Gets the result returned by the call() method in the newly created thread
                System.out.println("sum = " + ft.get());
            } catch (InterruptedException e) {
                e.printStackTrace();
            } catch (ExecutionException e) {
                e.printStackTrace();
            }

        }
    }
}

We can hardly find a familiar figure in the whole Demo. In fact, like inheriting Thread, it essentially implements the Runnable interface. Let's look at the definition of FutureTask.

public interface RunnableFuture<V> extends Runnable, Future<V> {
    /**
     * Sets this Future to the result of its computation
     * unless it has been cancelled.
     */
    void run();
}

So, although when we use the Callable interface, we find that we implement the call() method instead of run() and have a return value, it's actually the same.

Posted by mrherman on Sun, 19 May 2019 19:09:29 -0700