10_02.[Java]Multi-threading details--two implementation methods of multi-threading

An overview of multithreading

1. The running mode of the thread

In order to run multiple tasks at the same time, Java introduces the concept of multithreading. In Java, you can start multi-threaded mode in a convenient and fast way. Multithreading is often used in programs that conform to concurrency mechanisms, such as network programs.

The human body can carry out activities such as breathing, blood circulation, thinking about problems at the same time, and can chat while listening to songs... This mechanism is called a concurrency mechanism in Java. Through the concurrency mechanism, multiple threads can be executed concurrently, so that multi-threading comes into being. gave birth.

Take the running mode of multithreading in the Windows operating system as an example, the Windows operating system is a multitasking operating system, and it takes a process as a unit. Each independently executed program is called a process, such as QQ, WeChat, Google Chrome, etc. that are only running. Each is a process, and each process contains multiple threads. The system can assign each process a period of time to use the CPU, and then the CPU executes a process during this time, and each thread in the process is also assigned a small period of execution time, so that a process can have multiple threads executing concurrently the rout. Next, another process is executed in the next CPU time period. Due to the faster CPU switching, each process can be made to appear to be executed at the same time.

The operation mode of multithreading in Windows operating system is as follows:

2. The four states of the thread

  • New state: Thread has been created but not yet assigned (start() has not been called)
  • Executable state: The thread can execute, although not necessarily executing. CPU time may be allocated to this thread at any time.
  • Death state: Under normal circumstances, the return of the run() method causes the thread to die, and an exception will be generated at this time. Calling stop() or destroy() has the same effect, but stop and destroy are not recommended because they are forced planting and will not release locks.
  • Blocking state: The thread has not been allocated CPU time and cannot execute.

3. Implementation of multi-threading

Java provides two ways to implement multithreading, namely inheriting the java.lang.Thread class and implementing the java.lang.Runnable interface.

  • Inheriting the Thread class to override the run() method to implement multithreading

  • Multithreading through the Runnable interface

2. Inherit the Thread class to override the run() method to achieve multi-threading

1. Inheriting the Thread class to override the run() method to implement multi-threading steps

The Thread class is a class in the java.lang package. The object of the Thread class is used to represent the thread. The steps to create, start and execute a thread by inheriting the Thread class are as follows:

  • Create a subclass that inherits the Thread class;

  • Override the run() method of the Thread class;

  • Create an object of the thread class;

  • Start the thread by calling the start() method of the thread class object (the overridden run() method will be automatically called to execute the thread after startup). These four steps are detailed below:

(1) Create a subclass that inherits the Thread class

The two constructors of the Thread class are as follows:

  • public Thread(): Create a new thread.
  • public Thread(String threadName): Create a thread object named threadName

The syntax is as follows:

public class ThreadTest extends Thread{
  //code
  private int count = 10;
}

After creating a new thread, if you need to manipulate the created new thread, you need to use the methods provided by the Thread class. The common methods of the Thread class are as follows:

modifier/type method describe
void interrupt() interrupt the thread.
void join() Wait for this thread to terminate.
void join(long millis) The maximum time to wait for this thread to terminate is millis milliseconds.
void run() If the thread was constructed using a standalone Runnable run object, the run method of that Runnable object is called; otherwise, the method does nothing and returns.
static void sleep(long millis) Sleeps (pauses execution) the currently executing thread for the specified number of milliseconds plus the specified number of nanoseconds, subject to the precision and accuracy of system timers and schedulers.
static void sleep(long millis, int nanos) Sleeps (pauses execution) the currently executing thread for the specified number of milliseconds plus the specified number of nanoseconds, subject to the precision and accuracy of system timers and schedulers.
void start() Causes the thread to start executing; the Java virtual machine calls the thread's run method.
static void yield() Pause the currently executing thread object and execute other threads.

For more Thread methods, please see Multithreading (Details of Thread class and Runnable interface) in the Thread class section.

(2) Override the run() method of the Thread class

After inheriting a Thread class, rewrite the run() method in the thread class, write the code that implements the thread function into the run() method, and then call the start() method of the Thread class to start the thread. In the future, the overridden run() method will be automatically called to execute the thread.

The Thread class object needs a task to execute. The task refers to the work performed by the thread after it is started. The code of the task is written in run(). The run() method must be overridden using the following syntax:

public void run(){
  //code
}

(3) Create an object of the thread class

The thread object is created in the main method using the following syntax:

public static void main(String[] args){
  ThreadTest test = new ThreadTest();
}

(4) Start the thread

When the Java virtual machine calls the main method of the Java program, the main thread is started. If we want to start other programs, we need to call the start() method through the thread class object:

public static void main(String[] args){
  ThreadTest test = new ThreadTest();    //Create thread object
  test.start();                          //start thread
}

⚠️Note: If the start() method calls an already started thread, the system will throw an IllegalThreadException exception.

2. Inherit the Thread class to implement multi-threaded applications

Example 1: Inherit the Thread class, override the run() method to create and start a thread

public class ThreadTest extends Thread{
  private int count = 10;
  @Override
  public void run(){
  while(true){                      //Make the count variable decrement, and when it decrements to 0, exit the loop
    System.out.println(count+" ");
    if(--count == 0){
      break;
    }
  }
}
  public static void main(String[] args){
  ThreadTest test = new ThreadTest();
  test.start();
}
}
Console:
10 
9 
8 
7 
6 
5 
4 
3 
2 
1 

Example 2: Inheriting the Thread class to create multiple threads and start multiple threads

Create a multi-thread, including listening to music and eating, and write the main thread to call the start() method to start the thread.

  • Thread 1: Listening to music
import java.util.Date;

class ListenThread extends Thread {
    @Override
    public void run() {
        System.out.println("start listening to music" + new Date());
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("music off" + new Date());
    }
}
  • Thread 2: Eating
import java.util.Date;

class EatThread extends Thread{
    @Override
    public void run() {
        System.out.println("start eating" + new Date());
        try {
            Thread.sleep(5000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("end the meal" + new Date());
    }
}
  • Thread 3: Main thread
public class Main {
    public static void main(String[] args) {
	    // listening to music while eating
        new EatThread().start();
        new ListenThread().start();
    }
}
Console: 
start listening to music Thu Nov 12 17:59:19 CST 2020
 start eating Thu Nov 12 17:59:19 CST 2020
 music off Thu Nov 12 17:59:24 CST 2020
 end the meal Thu Nov 12 17:59:24 CST 2020

Three, through the Runnable interface to achieve multi-threading

If the current class not only inherits other classes (non-Thread), but also implements multi-threading, how should it be handled? Inheriting the Thread class is definitely not possible, because Java does not support multiple inheritance. In this case, the Thread class object can only be created by the current class implementing the Runnable interface.

1. Implementation of Runnable interface

A subclass of the Object class implements the Runnable interface with the following syntax:

public class ThreadTest extends Object implements Runnable{
  //code
}

🌿 Note: From the Java API, it can be found that the Thread class has implemented the Runnable interface, and the run() method of the Thread class is the specific implementation of the run() method in the Runnable interface.

2. Thread constructor whose parameter is Runnable object

A program implementing the Runnable interface creates a Thread object and associates the Runnable object with the Thread object. There are some constructors in the Thread class:

Construction method describe
Thread() Allocate a new Thread object.
Thread(Runnable target) Allocate a new Thread object and use the object target of the Runnable interface as its running object.
Thread(Runnable target, String name) Allocate a new Thread object so that the named object target that implements the Runnable interface is used as its running object.
Thread(String name) Allocate a new Thread object.
Thread(ThreadGroup group, Runnable target) Allocate a new Thread object.
Thread(ThreadGroup group, Runnable target, String name) Allocates a new Thread object with target as its run object, the specified name as its name, and as a member of the thread group referenced by group.
Thread(ThreadGroup group, Runnable target, String name, long stackSize) Allocates a new Thread object with target as its run object, with the specified name as its name, as a member of the thread group referenced by group, and with the specified stack size.
Thread(ThreadGroup group, String name) Allocate a new Thread object.

We often use Thread(Runnable target) and Thread(Runnable target, String name) to create new Thread objects.

  • Thread(Runnable target): Create a new Thread object and use the object target of the Runnable interface as its running object.
  • Thread(Runnable target, String name): Create a new Thread object so that the named object target that implements the Runnable interface is used as its running object.

3. Steps to start multithreading using the Runnable interface

In the process of implementing multithreading using the Runnable interface, we need to

(1) Create a class that implements the Runnable interface

  • ①Implement the Runnable interface

  • ②Rewrite the run method to tell the system how the program should run

  • ③ In the implementation class, use the constructor of the Runnable object to create a Thread object, so that the task is executed in the thread.

(2) Create a class implemented by the test program

  • ④Create a test class for the Runnable implementation class

  • ⑤ Instantiate the test object and assign a thread to the instantiated object

  • ⑥ Call the start() method to start the thread

From the above steps, we can see that when creating a thread through the Runnable interface, you first need a class that implements the Runnable interface, and then create an object of this class. When implementing Runnable, a Thread object associated with the Runnable interface will be created. This object is created by the constructor in the Thread class. We need to use this Thread object to call the start() method in the Thread class to start the thread. We can look at the flowchart to help understand:

Below we explain the above steps in detail:

4. Implement multi-threaded applications through the Runnable interface

Example 3: Implementing multithreading through the Runnable interface

(1) Create a class that implements the Runnable interface

  • ① First, you need to create a class that implements the Runnable interface, named RunnableDemo

  • ②Rewrite the run() method

  • ③ Create a Thread class in RunnableDemo with the parameter as the constructor of the Runnable object

/*
A class that implements the Runnable interface
**/

//① First, you need to create a class that implements the Runnable interface, named RunnableDemo
class RunnableDemo implements Runnable {
	private Thread t;
	private String threadName;
  
  //③ Create a Thread class in RunnableDemo with the parameter as the constructor of the Runnable object
	public RunnableDemo(String name){
	  threadName = name;
	  System.out.println("create"+threadName);
	}
  
	//②Rewrite the run() method
	public void run() {
	  for (int i = 0; i < 5; i++) {
	    for (long k = 0; k < 100000000; k++) ;
	    System.out.println(threadName + ": " + i);
	  } 
	}
  
}

(2) Create a thread object operation class

  • ④Create a test class TestRunnable implemented by RunnableDemo

  • ⑤ Instantiate the RunnableDemo object and assign threads

  • ⑥ Call the start() method to start the thread

/*
The class implemented by the test program
**/

//④Create a test class TestRunnable implemented by RunnableDemo
public class TestRunnable {
	public static void main(String args[]) {
		//⑤ Instantiate the RunnableDemo object and assign threads
		RunnableDemo R1 = new RunnableDemo( "Thread_1");   //Instantiate the RunnableDemo object
		RunnableDemo R2 = new RunnableDemo( "Thread_2");
       
    Thread t1 = new Thread(R1);                     //Allocate a thread for instantiating an object
    Thread t2 = new Thread(R2);
       
		//⑥ Call the start() method to start the thread
		t1.start();
		t2.start();
	}
}
Console:

create Thread_1
 create Thread_2
Thread_2: 0
Thread_1: 0
Thread_1: 1
Thread_2: 1
Thread_1: 2
Thread_2: 2
Thread_1: 3
Thread_2: 3
Thread_1: 4
Thread_2: 4

Example 4: Implementing multithreading through the Runnable interface requires rewriting the start() method

(1) Create a class that implements the Runnable interface

  • ① First, you need to create a class that implements the Runnable interface, named RunnableDemo

  • ②Rewrite the run() method and the start() method, and allocate threads in the start method

  • ③ Create a Thread class in RunnableDemo with the parameter as the constructor of the Runnable object

/*
A class that implements the Runnable interface
**/

//① First, you need to create a class that implements the Runnable interface, named RunnableDemo
class RunnableDemo implements Runnable {
	private Thread t;
	private String threadName;
  
  //③ Create a Thread class in RunnableDemo with the parameter as the constructor of the Runnable object
	public RunnableDemo(String name){
	  threadName = name;
	  System.out.println("create"+threadName);
	}
  
	//②Rewrite the run() method and the start() method, and allocate threads in the start method
	public void run() {                             //Override the run() method
	  for (int i = 0; i < 5; i++) {
	    for (long k = 0; k < 100000000; k++) ;
	    System.out.println(threadName + ": " + i);
	  } 
	}
  
  public void start () {                           //Override the start() method
		System.out.println("start up " +  threadName );
		if (t == null) {
			t = new Thread (this, threadName);
			t.start ();
		}
	}
  
}

(2) Create a thread object operation class

  • ④Create a test class TestRunnable implemented by RunnableDemo

  • ⑤ Instantiate the RunnableDemo object

  • ⑥ Call the rewritten start() method to start the thread

/*
The class implemented by the test program
**/

//④Create a test class TestRunnable implemented by RunnableDemo
public class TestRunnable {
	public static void main(String args[]) {
    
		//⑤ Instantiate the RunnableDemo object
		RunnableDemo R1 = new RunnableDemo( "Thread_1");
		RunnableDemo R2 = new RunnableDemo( "Thread_2");
    
		//⑥ Call the rewritten start() method to start the thread
		R1.start();
		R2.start();
    
	}
}
Console:

create Thread_1
 create Thread_2
 start up Thread_1
 start up Thread_2
Thread_2: 0
Thread_1: 0
Thread_1: 1
Thread_2: 1
Thread_1: 2
Thread_2: 2
Thread_1: 3
Thread_2: 3
Thread_1: 4
Thread_2: 4

⚠️Note: The above example 3 and example 4 both implement multi-threading through Runnable, and the implementation process of the two is the same. Taking such an example, I want to emphasize that the implementation class of the Runnable interface is not only the run() method, we In many cases, there are other methods other than the run method that need to be overridden.

have to be aware of is:

  • When we use methods in interfaces or classes, in many cases, we need to rewrite many methods according to business needs.

  • The idea of ​​the three major characteristics of classes (inheritance, polymorphism, and encapsulation) runs through Java programs.

  • The program is not static, we have to accept the flexibility of the program under a unified framework.

  • Only by constantly consolidating the foundation and thinking more can we be more comfortable in learning advanced programming knowledge.

Fourth, encourage the use of Runnable interface to create multi-threading

  • Avoids the limitations of single inheritance of the Thread class.

    • A class can only inherit from a single class, and a class that inherits the Thread class cannot inherit other classes; and implements the Runnable interface, it can also inherit other classes and implement other interfaces.
  • Implementing the Runnable interface reduces the coupling between thread objects and thread tasks, and enhances program scalability.

    • The way to implement the Runnable interface separates the thread task setting and the opening of a new thread (decoupling) into the implementation class;
    • Override the run method to set the thread task;
    • Create a Thread class object and call the start method to start a new thread;
    • Create a Thread class object, pass the implementation class object of the Runnable interface in the constructor, and pass different implementation classes (extensibility)
  • Implementing the Runnable interface encapsulates the thread separately to the object, which is more in line with the object-oriented idea.

Tags: Java

Posted by brian183 on Sat, 07 May 2022 22:42:47 +0300