preface

Java provides built-in support for multithreaded programming. A thread is a single sequential flow of control in a process, and multiple threads can be concurrent in a process, each performing a different task in parallel.

Multithreading is a special form of multitasking, but it uses less resource overhead.

Another thread-related term is defined here – process: a process consists of memory allocated by the operating system and contains one or more threads. A thread cannot exist on its own; it must be part of a process. A process runs until all non-daemons have finished running.

Multithreading can satisfy programmers to write efficient programs to make full use of CPU.

The life cycle of a thread

Threading is a process that executes dynamically, and it also has a process from birth to death.

The following figure shows the complete life cycle of a thread.

1. New state:

When a Thread object is created using the new keyword and the Thread class or its subclasses, the Thread object is created. It remains in this state until the program starts () thread.

2. Ready state:

When the thread object calls the start() method, the thread enters the ready state. A thread in a ready state is in a ready queue, waiting to be scheduled by the thread scheduler in the JVM.

3. Running state: If the ready thread acquires CPU resources, run() can be executed and the thread is running. The running thread is the most complex, and can be blocked, ready, or dead.

4. Blocking state:

If a thread executes methods such as sleep or suspend and loses occupied resources, the thread goes from running to blocked. You can re-enter the ready state when it is time to sleep or after obtaining device resources. It can be divided into three categories:

  • Wait to block: A running thread executes wait() to put the thread into the wait to block state.
  • Synchronized blocking: a thread fails to acquire a synchronized lock (because it is occupied by another thread).
  • Other blocking: The thread is blocked when an I/O request is made by calling the thread’s sleep() or join(). When the sleep() state times out, join() waits for the thread to terminate or time out, or the I/O process completes, and the thread reverts to the ready state.

5. Dead state: When a running thread completes a task or other termination conditions occur, the thread switches to the terminated state.

Second, thread priority

Each Java thread has a priority, which helps the operating system determine the order in which threads are scheduled.

The priority of a Java Thread 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. However, thread priority does not guarantee the order in which threads are executed and is very platform dependent.

Create a thread

Java provides three ways to create threads:

  • By implementing the Runnable interface;
  • By inheriting the Thread class itself;
  • Create threads through Callable and Future.

Create threads by implementing the Runnable interface

The easiest way to create a thread is to create a class that implements the Runnable interface.

To implement Runnable, a class only needs to make a single method call to run(), declared as follows:

public void run()
Copy the code

You can override this method, but it’s 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.

Thread defines several constructors. The following is the one we often use:

Thread(Runnable threadOb,String threadName);
Copy the code

Here, threadOb is an instance of a class that implements the Runnable interface, and threadName specifies the name of the new thread.

It doesn’t run until you call its start() method after a new thread is created.

void start();
Copy the code

Here is an example of creating a thread and starting it to execute:

The instance

class RunnableDemo implements Runnable {
   private Thread t;
   private String threadName;
   
   RunnableDemo( String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }
   
   public void run() {
      System.out.println("Running " +  threadName );
      try {
         for(int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ","+ i); Thread.sleep(50); } }catch (InterruptedException e) { System.out.println("Thread " +  threadName + " interrupted.");
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }
   
   public void start () {
      System.out.println("Starting " +  threadName );
      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
}
 
public class TestThread {
 
   public static void main(String args[]) {
      RunnableDemo R1 = new RunnableDemo( "Thread-1");
      R1.start();
      
      RunnableDemo R2 = new RunnableDemo( "Thread-2"); R2.start(); }}Copy the code

The result of compiling the above program is as follows:

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.
Copy the code

Create threads by inheriting threads

The second way to create a Thread is to create a new class that inherits the Thread class, and then create an instance of that class.

The inherited class must override the run() method, which is the entry point for the new thread. It must also call the start() method to execute.

Although listed as a multithreaded implementation, this method is essentially an instance of implementing the Runnable interface.

The instance

class ThreadDemo extends Thread {
   private Thread t;
   private String threadName;
   
   ThreadDemo( String name) {
      threadName = name;
      System.out.println("Creating " +  threadName );
   }
   
   public void run() {
      System.out.println("Running " +  threadName );
      try {
         for(int i = 4; i > 0; i--) {
            System.out.println("Thread: " + threadName + ","+ i); Thread.sleep(50); } }catch (InterruptedException e) { System.out.println("Thread " +  threadName + " interrupted.");
      }
      System.out.println("Thread " +  threadName + " exiting.");
   }
   
   public void start () {
      System.out.println("Starting " +  threadName );
      if (t == null) {
         t = new Thread (this, threadName);
         t.start ();
      }
   }
}
 
public class TestThread {
 
   public static void main(String args[]) {
      ThreadDemo T1 = new ThreadDemo( "Thread-1");
      T1.start();
      
      ThreadDemo T2 = new ThreadDemo( "Thread-2"); T2.start(); }}Copy the code

The result of compiling the above program is as follows:

Creating Thread-1
Starting Thread-1
Creating Thread-2
Starting Thread-2
Running Thread-1
Thread: Thread-1, 4
Running Thread-2
Thread: Thread-2, 4
Thread: Thread-1, 3
Thread: Thread-2, 3
Thread: Thread-1, 2
Thread: Thread-2, 2
Thread: Thread-1, 1
Thread: Thread-2, 1
Thread Thread-1 exiting.
Thread Thread-2 exiting.
Copy the code

6. Thread method

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

Tests whether the thread is active. The above methods are called by the Thread object. The following methods are static methods of the Thread class.

The instance

The following ThreadClassDemo program demonstrates some methods of the Thread class:

Displaymessage. Java file code:

// File name: Displaymessage. Java public class DisplayMessage implements Runnable {private String message; public DisplayMessage(String message) { this.message = message; } public voidrun() {
      while(true) { System.out.println(message); }}}Copy the code

Guessanumber.java file:

Public class GuessANumber extends Thread {private int number; public GuessANumber(int number) { this.number = number; } public voidrun() {
      int counter = 0;
      int guess = 0;
      do {
         guess = (int) (Math.random() * 100 + 1);
         System.out.println(this.getName() + " guesses " + guess);
         counter++;
      } while(guess ! = number); System.out.println("** Correct!" + this.getName() + "in" + counter + "guesses.**"); }}Copy the code

Threadclassdemo.java file code:

// File name: ThreadClassDemo.java public class ThreadClassDemo { public static void main(String [] args) { Runnable hello = new DisplayMessage("Hello");
      Thread thread1 = new Thread(hello);
      thread1.setDaemon(true);
      thread1.setName("hello");
      System.out.println("Starting hello thread...");
      thread1.start();
      
      Runnable bye = new DisplayMessage("Goodbye");
      Thread thread2 = new Thread(bye);
      thread2.setPriority(Thread.MIN_PRIORITY);
      thread2.setDaemon(true);
      System.out.println("Starting goodbye thread...");
      thread2.start();
 
      System.out.println("Starting thread3...");
      Thread thread3 = new GuessANumber(27);
      thread3.start();
      try {
         thread3.join();
      }catch(InterruptedException e) {
         System.out.println("Thread interrupted.");
      }
      System.out.println("Starting thread4...");
      Thread thread4 = new GuessANumber(75);
      
      thread4.start();
      System.out.println("main() is ending..."); }}Copy the code

The results are as follows, and the results vary from run to run.

Starting hello thread...
Starting goodbye thread...
Hello
Hello
Hello
Hello
Hello
Hello
Goodbye
Goodbye
Goodbye
Goodbye
Goodbye
.......
Copy the code

Create threads with Callable and Future

  1. Create an implementation class for the Callable interface that implements the Call () method, which acts as the thread body and has a return value.
  2. Create an instance of the Callable implementation class that wraps the Callable object with a FutureTask class that wraps the return value of the Callable object’s call() method.
  3. Create and start a new Thread using the FutureTask object as the target of the Thread object.
  4. Call the Get () method of the FutureTask object to get the return value after the child thread completes execution.

The instance

public class CallableThreadTest implements Callable<Integer> {
    public static void main(String[] args)  
    {  
        CallableThreadTest ctt = new CallableThreadTest();  
        FutureTask<Integer> ft = new FutureTask<>(ctt);  
        for(int i = 0; i < 100; i++) { System.out.println(Thread.currentThread().getName()+"The value of the loop variable I 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);  
        }  
        returni; }}Copy the code

Compare the three ways to create a thread

  1. When creating multiple threads by implementing the Runnable or Callable interface, the thread class only implements the Runnable or Callable interface and can also inherit from other classes.
  2. If you need access to the currentThread, use this instead of thread.currentthread () to retrieve the currentThread.

The main concepts of threads

Here are some concepts you need to understand when multithreading:

  • Thread synchronization
  • Interthread communication
  • The thread deadlock
  • Thread control: suspend, stop, and resume

Ten, the use of multithreading

The key to using multithreading effectively is to understand that programs execute concurrently rather than sequentially. For example, if you have two subsystems that need to be executed concurrently, you need to use multithreading.

Through the use of multithreading, you can write a very efficient program. Note, however, that if you create too many threads, the program actually performs less efficiently, not more efficiently.

Remember, context switching overhead is also important, if you create too many threads, the CPU will spend more time context switching than executing the program!

Write in the last

Some attention! Don’t get lost!

Java scaffolding base continues to be updated!