Coding With Fun
Home Docker Django Node.js Articles Python pip guide FAQ Policy

Java multithreaded programming


May 10, 2021 Java


Table of contents


Java multithreaded programming

Java provides built-in support for multithreaded programming. A multithreaded program contains two or more parts that can run in a synth. Each part of the program is called a thread, and each thread defines a separate execution path.

Multithreaded is a special form of multi-tasking. Multithreading requires less overhead than multitasing.

Another term defined here that is related to threads: processes: a process consists of 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 ended running.

Multithreaded programs can be used by programmers to write very efficient programs to get the most out of the CPU because the CPU's idle time is kept to a minimum.


The life cycle of a thread

Threads go through various stages of their life cycle. The following illustration shows the complete life cycle of a thread.

Java multithreaded programming

  • New Thread

    When an instance (object) of the Thread class is created, the thread enters a new state (not started).
    For example: Thread t1-new Thread ();
  • Ready (runnable)
    The thread has been started and is waiting to be assigned to the CPU time slice, which means that the thread is queuing in the ready queue to get CPU resources.
    For example: t1.start();

  • Run
    The thread gets CPU resources and is performing a task (run() method, at which point the thread will run until the end unless the thread automatically abandons the CPU resources or a higher priority thread enters.

  • Blocked for some reason causes a running thread to give up the CPU and suspend its own execution, i.e. enter a blocked state.

    Sleeping: The sleep (long t) method allows threads to go to sleep. A sleeping thread can go into a ready state at a specified time.

    Waiting: Call the wait() method. (Call motify() method back to ready state)

    Blocked by another thread: Calls the suspend() method. (Call resume() method recovery)

  • Death When a thread is executed or killed by another thread, the thread goes into a dead state, and the thread can no longer enter a ready state to wait for execution.

    Natural termination: Terminated after the normal operation of the run() method

    Abnormal termination: The stop() method is called to terminate a thread


The priority of the thread

Each Java thread has a priority, which helps the operating system determine the order in which threads are scheduled. J ava priority is MIN_PRIORITY between MAX_PRIORITY (1) and (10). By default, each thread is assigned a priority NORM_PRIORITY (5).

Threads with a higher priority are more important to the program, and processor time should be allocated before low priority threads. However, thread priority does not guarantee the order in which threads perform 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 with 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.

In order to implement Runnable, a class only needs to make a method call run(), declaring as follows:

public void run()

You can override the method, and it is important to understand that run() can call other methods, use other classes, and declare variables just like the main thread.

After you create a class that implements the Runnable interface, you can instantiate a thread object in the class.

Thread defines several construction methods, and here's 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, you call its start() method before it runs.

void start();

Instance

Here's 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 run 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 the class.

The inheritance 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 approach is essentially an instance of implementing the Runnable interface.

Instance

// 通过继承 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.");
   }
}

The results of compiling the above program run 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:

Serial number Method description
1 public void start()
Get the thread to execute;
2 public void run()
If the thread is constructed with a separate runnable running object, the run method of the runnable object is called;
3 public final void setName(String name)
Change the thread name so that it is the same as the parameter name.
4 public final void setPriority(int priority)
Change the priority of the thread.
5 public final void setDaemon(boolean on)
Mark the thread as a guard thread or a user thread.
6 public final void join(long millisec)
The maximum waiting time for the thread to terminate is millis milliseconds.
7 public void interrupt()
Interrupt the thread.
8 public final boolean isAlive()
Test whether the thread is active.

Test whether the thread is active. T he above method is called by the Thread object. The following method is a static method of the Thread class.

Serial number Method description
1 public static void yield()
Pauses the thread object that is currently executing and executes other threads.
2 public static void sleep(long millisec)
Put the currently executing thread to sleep (pause) within a specified number of milliseconds, which is affected by the accuracy and accuracy of the system timer and scheduler.
3 public static boolean holdsLock(Object x)
True is returned when and only if the current thread keeps the monitor lock on the specified object.
4 public static Thread currentThread()
Returns a reference to the thread object that is currently executing.
5 public static void dumpStack()
Print the stack trace of the current thread to the standard error stream.

Instance

The following ThreadClassDemo program demonstrates some of the 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 file code:

// 文件名 : 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 file code:

// 文件名 : 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 results are as follows, with different results for each run.

Starting hello thread...
Starting goodbye thread...
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Hello
Starting thread3...
Hello
Hello
Starting thread4...
Hello
Hello
main() is ending...

Create threads with Callable and Future

  • 1. Create an implementation class for the Callable interface and implement the call() method, which will act as a thread execution body and have a return value.
  • 2. Create an instance of the Callable implementation class and wrap the Callable object using the FutureTask class, which encapsulates the return value of the Call() method of the Callable object.
  • 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 a return value after the child thread executes.

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()+" 的循环变量i的值"+i);  
            if(i==20)  
            {  
                new Thread(ft,"有返回值的线程").start();  
            }  
        }  
        try  
        {  
            System.out.println("子线程的返回值:"+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;  
    }  
}

Create a comparison of the threads in three ways

  • 1. When you create a multithreaded interface by implementing the Runnable, Callable interface, the thread class simply implements the Runnable interface or the Callable interface, and you can inherit other classes.
  • 2. When creating multiple threads by inheriting thread classes, writing is simple, and if you need access to the current thread, you don't need to use the Thread.currentThread() method to get the current thread directly with this.

Several key concepts of threading

When you're multithreaded programming, here are a few concepts you need to understand:

  • Thread synchronization

  • Interthread communication

  • Thread deadlock

  • Thread control: Suspend, stop, and resume


Multithreaded use

The key to effectively utilizing multithreaded is to understand that programs are executed concatenable rather than serially. For example, two subsysysses in a program need to be executed in a synth, which requires multithreaded programming.

By using multiple threads, you can write very efficient programs. Note, however, that if you create too many threads, the efficiency of program execution is actually reduced, not improved.

Keep in mind that context switching overhead is also important, and if you create too many threads, the CPU will spend more time switching in context than executing programs!