Introduction to the

Before multithreading, only one step could be executed at any time in our program, called single threading. In a single-threaded program, all program paths are executed sequentially, and the first must be executed before the next. The advantages of single thread are also obvious, compared with multi-thread, it is more stable, more expansible and easier to develop programs. However, because each task has to wait for the completion of a task before starting a new task, its efficiency is lower than multithreading, and sometimes the application will appear the phenomenon of suspended animation. The use of multithreading is beneficial to give full play to the functions of multiprocessors. By creating multithreaded processes, each thread running on one processor, the concurrency of the application is achieved, so that each processor is fully run. Multithreading is a very important aspect of Java learning and a basic skill that every Java programmer must master. This article is a summary of some basic knowledge about Java multithreading.

The difference between processes and threads

process

Process is the basic unit of resource allocation in an operating system. It is the basis of an operating system. It is the activity that occurs when a program and its data are executed sequentially on a processor. When a program is run in memory, it becomes a process. A process is a program that is running and has some independent functions. The essence of a process is an execution process in the operating system. It is dynamically produced and destroyed, and has its own life cycle and various running states. At the same time, a process has concurrency, which means that it can execute concurrently with other processes, moving forward at independent and unpredictable speeds. (PS: Concurrency and parallelism are different concepts. Parallelism refers to the simultaneous execution of two or more instructions on multiple processors at the same time. Parallelism refers to the fact that only one instruction is executed at a time, but multiple processes can be swapped by the CPU quickly, giving the impression that there are multiple executions at the same time.

thread

A thread is the basic unit of task scheduling and execution, also known as a lightweight process. A thread consists of a thread ID, a current instruction pointer (PC), a register set, and a stack. A thread does not own system resources, it only owns a few resources that are necessary at run time, but it can share all resources owned by that process with other threads that belong to the same process. A thread can only belong to one process, and a process can have multiple threads, but at least one thread.

The difference between the two
  1. Threads are scheduled as the basic unit of scheduling and allocation, and processes as the basic unit of owning resources
  2. Concurrency can run concurrently not only between processes, but also between multiple threads of the same process
  3. An owning resource process is a separate unit that owns resources. Threads do not own system resources but can access resources belonging to the process
  4. System overhead When creating or undoing a process, the system allocates and reclaims resources for it, resulting in a significantly higher system overhead than when creating or undoing a thread

How a thread is created

All Thread objects must be instances of Thread or its subclasses. There are three main ways to create threads in Java:

Method one inherits the Thread class

Step 1 defines a class that inherits from Thread, and then overrides its run method, whose contents represent the tasks to be completed by the Thread

Step 2 Creates a Thread object, that is, an instance of a Thread subclass

Step 3 Calls the start method of the object created in Step 2 to start the thread

/ * * *@author mghio
 * @date: 2019-12-07
 * @version: 1.0
 * @descriptionThreads are created by inheriting the Thread class@sinceJDK 1.8 * /
public class CreateThreadByExtendsThread extends Thread {

  @Override
  public void run(a) {
    IntStream.rangeClosed(1.10).forEach(i -> System.out.println(Thread.currentThread().getName() + "" + i));
  }

  public static void main(String[] args) {
    CreateThreadByExtendsThread threadOne = new CreateThreadByExtendsThread();
    CreateThreadByExtendsThread threadTwo = new CreateThreadByExtendsThread();
    CreateThreadByExtendsThread threadThree = newCreateThreadByExtendsThread(); threadOne.start(); threadTwo.start(); threadThree.start(); }}Copy the code
Method 2 Implements the Runnable interface

Step 1 defines a class that implements the Runnable interface and then implements its Run method, the contents of which also represent tasks to be completed by the thread

Step 2 creates an instance of the Runnable interface implementation class and uses it as an argument to the Thraed constructor to create an object of the Thread class, which is the real Thread object

Step 3 calls the start method of the thread object to start the thread

/ * * *@author mghio
 * @date: 2019-12-07
 * @version: 1.0
 * @description: Creates threads * by implementing the Runnable interface@sinceJDK 1.8 * /
public class CreateThreadByImplementsRunnable implements Runnable {

  @Override
  public void run(a) {
    IntStream.rangeClosed(1.10).forEach(i -> System.out.println(Thread.currentThread().getName() + "" + i));
  }

  public static void main(String[] args) {
    CreateThreadByImplementsRunnable target = new CreateThreadByImplementsRunnable();
    new Thread(target, "thread-one").start();
    new Thread(target, "thread-two").start();
    new Thread(target, "thread-three").start(); }}Copy the code
Method three Implements the Callable interface

Step 1 defines a class that implements the Callable interface and then implements its Call method, whose contents also represent tasks to be completed by the thread and return values

Step 2 creates an instance of the Callable interface implementation class and wraps the Callable object with a FutureTask class that encapsulates the return value of the Callable object’s call method

Step 3 and create a Thread object using FutureTask as an argument to the Thraed constructor, and call the object’s start method to start the Thread

Step 4 calls the Get method of the FutureTask object to get the return value after the thread completes execution

/ * * *@author mghio
 * @date: 2019-12-07
 * @version: 1.0
 * @description: Creates threads * by implementing the Callable interface@sinceJDK 1.8 * /
public class CreateThreadByImplementsCallable implements Callable<Integer> {

  @Override
  public Integer call(a) {
    AtomicInteger count = new AtomicInteger();
    IntStream.rangeClosed(0.10).forEach(i -> {
      System.out.println(Thread.currentThread().getName() + "" + i);
      count.getAndIncrement();
    });

    return count.get();
  }

  public static void main(String[] args) {
    CreateThreadByImplementsCallable target = new CreateThreadByImplementsCallable();
    FutureTask<Integer> futureTask = new FutureTask<>(target);

    IntStream.rangeClosed(0.10).forEach(i -> {
      System.out.println(Thread.currentThread().getName() + "The value of the loop variable I of + i);
      if (i == 8) {
        new Thread(futureTask, "Thread with return value").start(); }});try {
      System.out.println("Return value of thread with return value:" + futureTask.get());
    } catch(InterruptedException | ExecutionException e) { e.printStackTrace(); }}}Copy the code

Threads are created by implementing Runnable and Callable interfaces in the same way. Threads are created by implementing Runnable and Callable interfaces in the same way. Java single inheritance decision). In this way, multiple threads can share the same target object, making it ideal for multiple threads working on the same resource. If you need access to the currentThread, use this instead of thread.currentthread () to retrieve the currentThread. In the actual project, if these three ways are used to create threads, system resources will be consumed if they are frequently created and closed, and performance will be affected. However, using thread pool can be put back to the thread pool when threads are not needed, and then taken from the thread pool when they are used. Therefore, thread pool is mainly used in our project development. For details on thread pools, see Java Thread Pools (I) and Java Thread Pools (II).

Several states of a thread

A thread is a dynamically executed process, and it also has a process from birth to death. In Java, the complete life cycle of a thread consists of the following five states:

When a Thread object is created using the New keyword and the Thread class or one of its subclasses, the Thread enters the New state, just like any other Java object, where the JVM allocates memory and initializes the values of its member variables. It remains in this state until the object’s start method is called.

When a thread object calls the start method, the thread enters the Runnable state. Ready threads are placed in a ready queue, waiting to be scheduled by a scheduler in the JVM. A thread in the ready state can be scheduled by the CPU at any time.

If the ready execution is scheduled by the CPU, the run method can be executed, and the thread is thread-state. The running thread is the most complex, and can be blocked, ready, or dead. It is important to note that a thread can only be in a ready state until it becomes running.

A thread becomes Blocked because it has given up CPU usage for some reason and is temporarily suspended. When methods such as sleep and suspend are executed to release occupied resources, the thread enters the Blocked state from running. Wait for the end of the sleep period or obtain equipment resources to re-enter the ready state. Blocking can be divided into the following three types:

  1. Waiting for blockingIn aRunning stateThread callwaitMethod, which causes the thread to enterWait blocked state
  2. A synchronized blockWhen the thread getssynchronizedA synchronization lock fails because the synchronization lock is occupied by another threadA synchronized block
  3. Other blockBy calling the threadsleeporjoinWhen an I/O request is made, the thread enters a blocked state. whensleepStatus timeout,joinWait until the thread terminates or times out, or the thread returns after I/O processing is completeThe ready state.

When a running thread finishes executing a run method or other termination conditions occur, it enters the Dead state and terminates its life cycle. The flow of the various states of the above threads is shown in a graph as follows:

Common thread methods

Methods commonly used in threads can be divided into two categories according to their sources. One is the method inherited from the Object class, as shown below:

methods describe
public final native void notify() Wakes up a single thread waiting on this object monitor to enterThe ready state
public final native void notifyAll() Wakes up all threads waiting on this object monitor to enterThe ready state
public final void wait() Let the current thread be in ·Wait blocked stateUntil another thread calls the object’snotifyMethod ornotifyAllMethod, the current thread is awakened to release the lock it holds
public final native void wait(long timeout) Let the current thread be in ·Wait blocked stateUntil another thread calls the object’snotifyMethod ornotifyAllMethod, the current thread is awakened
public final void wait(long timeout, int nanos) Let the current thread be in ·Wait blocked stateUntil another thread calls the object’snotifyMethod ornotifyAllMethod or another thread interrupts the current thread, or the current thread is woken up after an actual amount of time has elapsed

The other class is the method defined by Thread, as follows:

methods describe
public static native void yield() Suspends the currently executing thread object and executes another thread,yieldMethod does not release the lock
public static native void sleep(long millis) Hibernate (suspend execution) the currently executing thread for the specified number of milliseconds,sleepMethod does not release the lock
public final void join() When a program calls another thread in the execution streamjoinMethod, the calling thread will block until calledjoinThe thread has finished executing
public void interrupt() Used to interrupt the thread. When called, this method immediately sets the thread’s interrupt flag totrue
public static boolean interrupted() ThreadClass that returns a Boolean indicating whether the current thread has been interrupted,interruptedMethod in addition to returning the interrupt flag, it clears the interrupt flag (setting the interrupt flag tofalse)
public boolean isInterrupted() ThreadClass, which returns a Boolean indicating whether the current thread has been interrupted,isInterruptedMethod only returns the interrupt flag, not the endpoint flag

Priority of the thread

Each Java thread has a priority, which helps the operating system determine the order in which threads are scheduled. The priority of Java threads is an integer ranging from 1 (thread.min_priority) to 10 (thread.max_priority). By default, each thread is assigned a priority of NORM_PRIORITY (5). Threads with higher priority are more important to the program, and processor resources should be allocated before threads with lower priority. The Thread class provides setPriority and getPriority methods to change and get Thread priorities (note: Thread priorities do not guarantee the order in which threads are executed and are very platform dependent).


Refer to the article

  • The difference between processes and threads
  • Java Multithreading series – Thread wait and wake up in Basics 05