Multithreading and threading source code analysis

What is multithreading

Multithreading is the smallest unit that the operating system can schedule. It is included in the process and is the actual operation unit of the process. The number of hardware CPU cores corresponds to the number of threads that can be executed at the same time.

Specific evolution path

IO database interaction, disk brushing, caching, distributed, middleware and threads are everywhere from single node to distributed computer.

Why use threads

From the start of a program to the running of a process, the CPU is required to schedule execution, but the CPU computing speed is much faster than the disk IO computing storage, then the difference CPU in the middle will be in a waiting state, that is, blocking, resulting in a waste of CPU resources.
All leads to multiple processes and then to multiple threads. A process can have N threads

Multithreading in Java

1. Multithreading features

  • asynchronous

I don't have to wait for the result to come back. After I send the request, I don't have to wait for the result, and then I can do other things
Specific embodiment: after the user registers, then asynchronously draw and send e-mail, etc

  • parallel

I can draw a lottery and send a welcome email at the same time. It is used when there is no association between the two threads

2. Use in Java

  • There are three ways to use them. See the following code respectively
class Test0 extends Thread{
    @Override
    public void run() {
        System.out.println("inherit Thread");
    }
}

class Test1 implements Runnable{

    @Override
    public void run() {
        System.out.println("realization Runnable Interface");
    }
}

class Test2 implements Callable {

    @Override
    public Object call() throws Exception {
        System.out.println("realization Callable Interface,And get the return value");
        Thread.sleep(10000);
        return "call Thread return value";
    }
}

//main method call
public static void main(String[] args) throws Exception {
    //Inherit Thread
    new Test0().start();
    //Implement Runnable interface
    new Thread(new Test1()).start();
    //Implement the callable interface to obtain the return value
    Test2 test2 = new Test2();
    FutureTask<Object> task = new FutureTask<Object>(test2);
    //Here, the jvm first calls the run method in FutureTask, and then calls result = c.call(); To our implementation method
    //And save the result to the variable outcome
    new Thread(task).start();
    //Get the results through report and wait before the execution is finished
    System.out.println(task.get());
}

Principle of multithreading

1. Source code analysis, start here

class Test0 extends Thread{
    @Override
    public void run() {
        System.out.println("inherit Thread");
    }
}

2. Start thread

	//The start method starts a thread, and run() executes synchronously once
	new Test0().start(); 
	//Come to the Thread class
    public synchronized void start() {
        if (threadStatus != 0)
            throw new IllegalThreadStateException();

        //Join to thread group
        group.add(this);

        boolean started = false;
        try {
            //Mainly look at this###
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }
	//The next discovery is the native method
    private native void start0();

The above native method is finally called into the JVM thread.cpp, and then the JVM creates a thread according to the corresponding OS that will be called by different operating systems, and this method will tell the cpu to start a thread. Then, when executing this thread in the cpu scheduling algorithm, it will call back to the JVM, and finally call the run method in the thread, that is, our handwritten code, and the thread starts to execute

3. Thread diagram

Thread life cycle

Enable - > sleep wait - > lock synchronized lock - > execution completion / abnormal end

When the thread is running, you can view the stack log through [jstack process number]

Thread stop

1. First look at the friendly end and stop through the interrupted interrupt instruction

		Thread thread = new Thread(() -> {
        	while (!Thread.currentThread().isInterrupted()) {
        		System.out.println(11111);
        	}
        }, "N1");
        thread.start();
        Thread.sleep(1000);
		//Stop through the interrupt ID of the current thread
        thread.interrupt();
        System.out.println(22222);

2. Violent end must be used when the block executed in the thread cannot end normally, such as dead loop, blocking and waiting

    public static void main(String[] args) throws InterruptedException {
        Thread thread = new Thread(() -> {
            while (!Thread.currentThread().isInterrupted()) {
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    System.out.println(3333);
                }
                System.out.println(11111);

            }
        }, "N1");
        thread.start();
        Thread.sleep(3000);
        //Sending an interrupt instruction will throw InterruptedException up
        thread.interrupted();
        System.out.println(22222);
    }
  • results of enforcement
11111
11111
22222
3333
11111
11111
  • From the above results, we can see that the code will not stop at all, but will run all the time. When the interrupt instruction is sent, why not stop? Look at these two pieces of code first
 try {
     Thread.sleep(1000);
 } catch (InterruptedException e) {
     System.out.println(3333);
 }
try {
    Thread.currentThread().wait();
} catch (InterruptedException e) {
    e.printStackTrace();
}
  • All waiting or blocking operations of the thread will throw this exception, because it may be waiting or blocking all the time, so the thread interrupt is required. However, the thread is clearly interrupted but does not stop. This process is called thread interrupt reset
	 try {
         Thread.sleep(1000);
     } catch (InterruptedException e) {
         //The choice here lies with the developer himself 
         //After the InterruptedException exception is thrown, the interrupt state will be restored, which is called reset
         //Then, if you want to interrupt, use this Thread.currentThread().interrupt()
         //Then do something after the exception interrupt
         System.out.println(3333);
     }

3. Thread reset

When the thread interrupted ID is given, the current thread will not end immediately, but will throw an InterruptedException, which needs to be determined by the developer, because some other records may need to be made after the exception interrupt.
Let's look at code analysis

	public static boolean interrupted() {
		//Identify the current thread as true
        return currentThread().isInterrupted(true);
    }
    //Next, go to the native method, which is the operation done in the JVM
    //This thread is given an identity. When the thread reads the identity, it will throw an exception and reset the interrupted state
    private native boolean isInterrupted(boolean ClearInterrupted);

The above is the whole content of multithreading and threading into source code analysis.
Next: Troubleshooting of deadlock, livelock and sudden surge of CPU in Java Server

I have no intention of going or staying. I watch the flowers bloom and fall in front of the court; Not surprised by flattery or disgrace, it spreads with the clouds outside the sky

Keywords: Java Multithreading source code

Added by tomo11 on Tue, 30 Nov 2021 17:32:12 +0200