Fundamentals of Java multithreaded programming (day 18 of Java from self-study to employment)

Java learning record day 18

Since this slag is converted to Java at the front end, the selection of editor is directly used webstorm With the company idea
Some of the following knowledge will be learned from the boss Liao Xuefeng's blog

Learning objectives

What is multithreading and how to use it?

Learning content

  • Java multithreading
  • The life cycle of a thread
  • Create a thread by implementing the Runnable interface
  • Create a Thread by inheriting Thread
  • Creating threads through Callable and Future
  • Comparison and summary of three ways to create threads

Java multithreading

How to create a thread? Java provides three ways to create threads:

  1. Through the implementation of Runnable interface;
  2. By inheriting the Thread class itself;
  3. Create threads through Callable and Future.

Java provides built-in support for multithreaded programming. A thread refers to a single sequential control flow in a process. Multiple threads can be concurrent in a process, and each thread executes different tasks in parallel.
Multithreading is a special form of multitasking, but multithreading uses less resource overhead.
Another term related to threads is defined here - process: a process includes memory space allocated by the operating system and contains one or more threads. A thread cannot exist independently. It must be part of a process. A process runs until all non daemon threads have finished running.
Multithreading can satisfy programmers to write efficient programs to make full use of CPU.

Thread priority:

  • Each Java thread has a priority, which helps the operating system determine the scheduling order of threads.
  • The priority of Java thread is an integer, and its value range is 1 (Thread.MIN_PRIORITY) - 10 (Thread.MAX_PRIORITY).
  • By default, each thread is assigned a priority NORM_PRIORITY(5).
  • Threads with higher priority are more important to the program, and processor resources should be allocated before threads with lower priority. However, thread priority can not guarantee the order of thread execution, and it is very platform dependent.

The key to making effective use of multithreading is to understand that programs are executed concurrently rather than serially.
For example, there are two subsystems in the program that need to be executed concurrently. At this time, multithreading programming is needed.
Through the use of multithreading, we can write a very efficient program.
However, please note that if you create too many threads, the efficiency of program execution is actually reduced, not improved.
Remember that context switching overhead is also important. If you create too many threads, the CPU will spend more time on context switching than executing the program!

The life cycle of a thread

  • New status:
    • After using the new keyword and Thread class or its subclasses to create a Thread object, the Thread object is in the new state. It remains in this state until the program starts () the Thread.
  • Ready status:
    • When the thread object calls the start() method, the thread enters the ready state. The thread in the ready state is in the ready queue and needs to wait for the scheduling of the thread scheduler in the JVM.
  • Operation status:
    • If the thread in the ready state obtains CPU resources, it can execute run(), and the thread is in the running state. The thread in the running state is the most complex. It can change into blocking state, ready state and dead state.
  • Blocking status:
    • If a thread executes sleep, suspend and other methods, and loses its occupied resources, the thread will enter the blocking state from the running state. After the sleep time has expired or the device resources have been obtained, you can re-enter the ready state. It can be divided into three types:
      • Wait blocking: the thread in the running state executes the wait() method to make the thread enter the wait blocking state.
      • Synchronization blocking: the thread failed to acquire the synchronized synchronization lock (because the synchronization lock is occupied by other threads).
      • Other blocking: when an I/O request is issued by calling the thread's sleep() or join(), the thread will enter the blocking state. When the sleep() state times out, the join() waits for the thread to terminate or time out, or the I/O processing is completed, and the thread returns to the ready state.
  • Death status:
    • When a running thread completes a task or other termination conditions occur, the thread switches to the termination state.

Create a thread by implementing the Runnable interface

The easiest way to create a thread is to create a class that implements the Runnable interface.
In order to implement Runnable, a class only needs to execute a method call run()
You can override this method. It is important to understand that run() can call other methods, use other classes, and declare variables, just like the main thread.
After creating a class that implements the Runnable interface, you can instantiate a thread object in the class.
After the new thread is created, you call its start() method before it runs.

class RunnableDemo implements Runnable {
    private Thread t;
    private String threadName;

    public RunnableDemo(String name) {
        threadName = name;
        System.out.println("Create thread:" + threadName);
    }

    public void run() {
        System.out.println("Running thread:" + threadName);
        try {
            for (int i = 4; i > 0; i--) {
                System.out.println("Blocking status:" + threadName + ",The first " + i + " second");
                Thread.sleep(50);
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println(threadName + " Thread interrupt...");
        }
        System.out.println(threadName + " Thread end");
    }

    public void start() {
        System.out.println("thread  " + threadName + " Ready...");
        if (t == null) {
            t = new Thread(this, threadName);
            t.start();
        }
    }
}

public class Test1 {
    public static void main(String[] args) throws InterruptedException{
        RunnableDemo r1 = new RunnableDemo("Thread one");
        r1.start();

        RunnableDemo r2 = new RunnableDemo("Thread two");
        r2.start();
    }
}

For a simple example, the output is as follows:

Create a Thread by inheriting Thread

The following table lists some important methods of the Thread class:

methoddescribe
public void start()Start the thread to execute; The Java virtual machine calls the run method of the thread.
public void run()If the thread is constructed using an independent Runnable running object, call the run method of the Runnable object; Otherwise, the method does nothing and returns.
public final void setName(String name)Change the thread name to be the same as the parameter name.
public final void setPriority(int priority)Change the priority of the thread.
public final void setDaemon(boolean on)Mark the thread as a daemon or user thread.
public final void join(long millisec)The maximum time to wait for the thread to terminate is millis econds.
public void interrupt()Interrupt the thread.
public final boolean isAlive()Test whether the thread is active.

Test whether the Thread is active. The above methods are called by the Thread object, and the following methods are static methods of the Thread class:

methoddescribe
public static void yield()Pause the currently executing thread object and execute other threads.
public static void sleep(long millisec)Hibernate (pause execution) the currently executing thread for a specified number of milliseconds, which is affected by the accuracy and accuracy of the system timer and scheduler.
public static boolean holdsLock(Object x)Returns true if and only if the current thread holds a monitor lock on the specified object.
public static Thread currentThread()Returns a reference to the thread object currently executing.
public static void dumpStack()Prints the stack trace of the current thread to the standard error stream.
class DisplayMessage implements Runnable {
    private String msg;

    public DisplayMessage(String msg) {
        this.msg = msg;
    }

    public void run() {
        while (true) {
            System.out.println(msg);
        }
    }
}

class GuessANumber extends Thread {
    private Integer num;

    public GuessANumber(int num) {
        this.num = num;
    }

    public void run() {
        Integer counter = 0;
        Integer guess = 0;
        do {
            guess = (int) (Math.random() * 100 + 1);
            System.out.println(this.getName() + " Guess number:" + guess);
            counter++;
        } while (guess != num);
        System.out.println("congratulations " + this.getName() + "In the first " + counter + " Guess the number...");
    }
}

public class Test2 {
    public static void main(String[] args) throws InterruptedException {
        Runnable r1 = new DisplayMessage("I'm number one...");
        Thread t1 = new Thread(r1);
        t1.setDaemon(true);
        t1.setName("Player number one");
        System.out.println("Player one is ready...");
        t1.start();

        Runnable r2 = new DisplayMessage("I'm number two...");
        Thread t2 = new Thread(r2);
        t2.setPriority(Thread.MIN_PRIORITY); // Set minimum priority
        t2.setDaemon(true);
        System.out.println("Player number two is ready...");
        t2.start();

        System.out.println("Player number three is ready...The number to guess is: [3]");
        Thread t3 = new GuessANumber(3);
        t3.setName("Player number three");
        t3.start();
        try {
            t3.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
            System.out.println("Player No. 3 has an error in the program...");
        }

        System.out.println("Player number four is ready...The number to guess is: [8]");
        Thread t4 = new GuessANumber(8);
        t4.setName("Player number four");
        t4.start();

        System.out.println("Program end...");

    }
}

The code output is too long. If you are interested, you can run it yourself

Creating threads through Callable and Future

  1. Create the implementation class of the Callable interface and implement the call() method, which will be used as the thread executor and have a return value.
  2. Create an instance of the Callable implementation class, and use the FutureTask class to wrap the Callable object. The FutureTask object encapsulates the return value of the call() method of the Callable object.
  3. Use the FutureTask object as the target of the Thread object to create and start a new Thread.
  4. Call the get() method of the FutureTask object to get the return value after the execution of the child thread.
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;

public class Test3 implements Callable<Integer> {
    public static void main(String[] args) {
        Test3 ctt = new Test3();
        FutureTask<Integer> ft = new FutureTask<Integer>(ctt);

        for (int i = 0; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " Thread loop variable i Value of:" + i);
            if (i == 20) {
                new Thread(ft, "Thread with return value").start();
            }
        }

        try {
            System.out.println("Return value of child thread:" + ft.get());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } catch (ExecutionException e) {
            e.printStackTrace();
        }
    }

    @Override
    public Integer call() throws Exception {
        int i = 0;
        for (; i < 100; i++) {
            System.out.println(Thread.currentThread().getName() + " " + i);
        }
        return i;
    }
}

The code output is too long. If you are interested, you can run it yourself

Comparison and summary of three ways to create threads

  1. When multithreading is created by implementing Runnable and Callable interfaces, the thread class only implements the Runnable interface or Callable interface, and can also inherit other classes.
  2. When creating a multithread by inheriting the Thread class, it is easy to write. If you need to access the current Thread, you don't need to use Thread The currentthread() method can directly use this to obtain the current Thread.

Several main concepts of thread:

  1. Thread synchronization
  2. Inter thread communication
  3. thread deadlock
  4. Thread control: suspend, stop, and resume

Self study is not easy, praise and encourage.

Thank you for your attention. If there is anything wrong, please point it out and make progress together.

Keywords: Java Multithreading Concurrent Programming thread

Added by Brink Kale on Sun, 30 Jan 2022 15:15:48 +0200