Java multithreaded programming


Java provides built-in support for multi-threaded programming. A multithreaded program consists of two or more parts that can run concurrently. Each part of the program is called a thread, and each thread defines an independent execution path.

Multi-threading is a special form of multi-tasking, but multi-threading uses smaller resource overhead.

Here defines another term related to threads - process: A process includes the 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-waiting threads have finished running.

Multi-threading can satisfy programmers to write efficient programs to fully utilize the CPU.


The life cycle of a thread

The thread passes through various stages of its life cycle. The following figure shows the complete life cycle of a thread.

java-thread.jpg

  • New status:

    Use the new keyword and After the Thread class or its subclass creates a thread object, the thread object is in the newly created state. It remains in this state until the program start() this thread.

  • Ready state:

    When the thread object calls the start() method, the thread enters the ready state. Threads in the ready state are in the ready queue and are waiting for scheduling by the thread scheduler in the JVM.

  • Running status:

    If the thread in the ready state obtains CPU resources, it can execute run(), this When the thread is running. The thread in the running state is the most complex, it can become blocked, ready and dead.

  • Blocking state:

    If a thread executes sleep (sleep), suspend (suspend) and other methods, after losing the occupied resources , the thread enters the blocking state from the running state. The ready state can be re-entered after the sleep time has expired or device resources have been obtained.

  • Death state:

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


Thread priority

Each Java thread has a priority, which helps the operating system determine the scheduling order of threads.

The priority of a Java thread is an integer, and its value range is 1 (Thread.MIN_PRIORITY) - 10 (Thread.MAX_PRIORITY).

By default, each thread will be assigned a priority level NORM_PRIORITY (5).

Threads with higher priority are more important to the program and should be allocated processor resources before threads with lower priority. However, thread priority does not guarantee the order of thread execution and is very platform dependent.


Create a thread

Java provides two methods for creating threads:

  • By implementing the Runable interface;

  • By inheriting the Thread class itself.


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 called run(), declared as follows:


##

public void run()

You can override this method, important It is understood 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 construction methods, the following one is what we often use:

Thread(Runnable threadOb,String threadName);

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

After a new thread is created, it will not run until you call its start() method.

void start();

Example

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

// 创建一个新的线程
class NewThread implements Runnable {
   Thread t;
   NewThread() {
      // 创建第二个新线程
      t = new Thread(this, "Demo Thread");
      System.out.println("Child thread: " + t);
      t.start(); // 开始线程
   }
  
   // 第二个线程入口
   public void run() {
      try {
         for(int i = 5; i > 0; i--) {
            System.out.println("Child Thread: " + i);
            // 暂停线程
            Thread.sleep(50);
         }
     } catch (InterruptedException e) {
         System.out.println("Child interrupted.");
     }
     System.out.println("Exiting child thread.");
   }
}
 
public class ThreadDemo {
   public static void main(String args[]) {
      new NewThread(); // 创建一个新线程
      try {
         for(int i = 5; i > 0; i--) {
           System.out.println("Main Thread: " + i);
           Thread.sleep(100);
         }
      } catch (InterruptedException e) {
         System.out.println("Main thread interrupted.");
      }
      System.out.println("Main thread exiting.");
   }
}

The results of compiling the above program are as follows:

Child thread: Thread[Demo Thread,5,main]
Main Thread: 5
Child Thread: 5
Child Thread: 4
Main Thread: 4
Child Thread: 3
Child Thread: 2
Main Thread: 3
Child Thread: 1
Exiting child thread.
Main Thread: 2
Main Thread: 1
Main thread exiting.


Create a thread by inheriting Thread

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

Inherited classes must override the run() method, which is the entry point of the new thread. It must also call the start() method to execute.

Example

// 通过继承 Thread 创建线程
class NewThread extends Thread {
   NewThread() {
      // 创建第二个新线程
      super("Demo Thread");
      System.out.println("Child thread: " + this);
      start(); // 开始线程
   }
 
   // 第二个线程入口
   public void run() {
      try {
         for(int i = 5; i > 0; i--) {
            System.out.println("Child Thread: " + i);
                            // 让线程休眠一会
            Thread.sleep(50);
         }
      } catch (InterruptedException e) {
         System.out.println("Child interrupted.");
      }
      System.out.println("Exiting child thread.");
   }
}
 
public class ExtendThread {
   public static void main(String args[]) {
      new NewThread(); // 创建一个新线程
      try {
         for(int i = 5; i > 0; i--) {
            System.out.println("Main Thread: " + i);
            Thread.sleep(100);
         }
      } catch (InterruptedException e) {
         System.out.println("Main thread interrupted.");
      }
      System.out.println("Main thread exiting.");
   }
}

Compile the above program and run the results as follows:

Child thread: Thread[Demo Thread,5,main]
Main Thread: 5
Child Thread: 5
Child Thread: 4
Main Thread: 4
Child Thread: 3
Child Thread: 2
Main Thread: 3
Child Thread: 1
Exiting child thread.
Main Thread: 2
Main Thread: 1
Main thread exiting.


Thread method

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

## 1               2               3               4               5               6               7               8

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

Serial numberMethod description
public void start() Cause the thread to start executing;
Java The virtual machine calls the run method of the thread.
public void run() If the thread was constructed using a separate Runnable run object, the Runnable object's run method is called; 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 a thread.
public final void setDaemon(boolean on) Mark the thread as a daemon thread or user thread.
public final void join(long millisec) The maximum time to wait for this thread to terminate is millis milliseconds.
public void interrupt() Interrupt thread.
public final boolean isAlive() Tests whether the thread is active.
## 1               2               3               4               5
Serial numberMethod description
public static void yield() Pauses the currently executing thread object and executes other threads.
public static void sleep(long millisec) Causes the currently executing thread to sleep (pause execution) for a specified number of milliseconds, subject to the precision and accuracy of system timers and schedulers.
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 currently executing thread object.
public static void dumpStack() Prints the current thread's stack trace to the standard error stream.
Example

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

// 文件名 : DisplayMessage.java
// 通过实现 Runnable 接口创建线程
public class DisplayMessage implements Runnable
{
   private String message;
   public DisplayMessage(String message)
   {
      this.message = message;
   }
   public void run()
   {
      while(true)
      {
         System.out.println(message);
      }
   }
}
// 文件名 : GuessANumber.java
// 通过继承 Thread 类创建线程

public class GuessANumber extends Thread
{
   private int number;
   public GuessANumber(int number)
   {
      this.number = number;
   }
   public void run()
   {
      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.**");
   }
}
// 文件名 : 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...");
   }
}

The running results are as follows, the results of each run They are all different.

Starting hello thread...
Starting goodbye thread...
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Thread-2 guesses 27
Hello
** Correct! Thread-2 in 102 guesses.**
Hello
Starting thread4...
Hello
Hello
..........remaining result produced.

Several main concepts of threads:

In multi-threaded programming, you need to understand the following concepts:

  • Thread synchronization

  • Inter-thread communication

  • Thread deadlock

  • Thread control: suspend, stop and resume


The use of multi-threading

The key to effective use of multi-threading is to understand that programs execute concurrently rather than serially. For example: There are two subsystems in the program that need to be executed concurrently. In this case, multi-thread programming needs to be used.

Through the use of multi-threading, very efficient programs can be written. However, please note that if you create too many threads, the efficiency of program execution will actually be reduced, not improved.

Please remember that context switching overhead is also important. If you create too many threads, the CPU will spend more time switching contexts than executing the program!