Multi-threaded Learning Part 1

My whole life is full of regrets
Contented and determined, gentle and motivated
All in all, it’s been a long time, but it’s worth the wait.

v2-cd5b2ac4052af8ad220232245da91ed3_1440w

Get current thread reference

method illustrate
public static Thread currentThread(); Returns a reference to the current thread object

currentThread() => In that thread, you can get the instance of that thread.


static keyword

Static modified method~~ Literal translation~~ Static method (bad translation) => Class method (better term)
calls this method without an instance and calls it directly through the class name.
Thread t = new Thread;
Call this method above time, directly Thread.currentThread();
does not necessarily have tot.currrentThread;

Literally, there is no connection between the word static and class methods/class attributes.

static ~~ Issues left over from history

Java is designed this way because C++ is also designed this way. ~~ Many syntaxes in Java are borrowed from C++,
and C++ evolved from the C language. In the C language, static can modify global/variable variables and functions.
~ ~ In early operating systems, the memory area was divided into a "static memory area". The
initial role of static was that variables modified by static were in the "static memory area".
But later the "static memory area" disappeared. However, the static keyword is retained and given new functions.

With the introduction of classes and objects in C++, there is an urgent need for a way to express "class attributes" and "class methods". Just
take the previous static keyword and give it a new history regardless of its literal meaning. It's mission.

A new question is coming, why not create a new keyword to represent "class attributes, class methods", such as classmethod in Python? The reason is that
keywords have special meanings and cannot be used as variable names, function names, or Class name...
Once a new keyword is introduced, once the word of this keyword is used as a variable name in the thousands of originally written codes
, the code will not be compiled by the compiler.
However, This is unacceptable to programmers. It is impossible to rewrite so much code that cannot be compiled.

This matter mainly reflects "code compatibility".

Note: The functions of the C language we are learning now have changed.

Trivia: The C language has not changed much in the past twenty years. The big guys in the C standard committee are already messing around,
including Ken Thomson, the father of the C language, who has devoted himself wholeheartedly to the Go language ( Failure to update is a sign of demise).


Sleep the current thread

~~ Essentially, it means that this thread will not participate in scheduling (it will not be executed on the CPU)

method illustrate
public static void sleep(long millis) throws InterruptedException Sleep the current thread millis milliseconds
public static void sleep(long millis, int nanos) throws InterruptedException Can sleep with higher precision

image-20230921201912237

Note:
(1) PCB is organized using linked lists. (Not specific) The actual situation is not a simple linked list. In fact, it is a series of data structures with linked lists as the core. (2) The operating system needs to schedule each
time To execute a thread, just select one from the ready queue.
(3) Once the thread enters the blocking state, the corresponding PCB enters the blocking queue, and it is temporarily unable to participate in scheduling.
(4) This method can only guarantee actual sleep. The time is greater than or equal to the sleep time set by the parameter.
For example, if sleep(1000) is called, the corresponding thread PCB will wait in the blocking queue for 1000ms.
When this PCB returns to the ready queue, will it be scheduled immediately?
Although it is sleep(1000), in fact, considering the scheduling overhead , the corresponding thread cannot be executed immediately after waking up. The actual time interval is likely to be greater than 1000ms.

~~Hung up means blocking, which means one thing. School operating system classes generally use the term "hang" more often.

Thread status

The status describes the current thread scheduling situation.
Since the thread is the basic unit of scheduling, the status is the attribute of the thread.

Attributes illustrate personal understanding
1.NEW The work has been arranged, but the action has not been started yet The Thread object is created, but start has not been called yet (the corresponding PCB has not been created in the kernel)
2.TERMINATED work done Indicates that the PCB in the kernel has been executed, but the Thread object is still there
3.RUNNABLE Workable. It can also be divided into currently working and about to start working. Runnable (called RUNNABLE, but RUNNING)
(1) is being executed on the CPU
(2) is in the ready queue and can be executed on the CPU at any time
4, 5, and 6 all indicate that the thread PCB is blocking the queue. The three states 4, 5, and 6 are blocked for different reasons. 4, 5, and 6 all mean waiting in line for other things.
4.WAITING Indicates waiting in line for other things
5.TIMED_WAITING Indicates waiting in line for other things
6.BLOCKED Indicates waiting in line for other things

Note: The state of the thread is an enumeration type Thread.State. You can use
for (Thread.State state : Thread.State.values()) { System.out.println(state); } this code to print out the properties of the thread.

The meaning of thread state and state transfer

Detailed illustration

image-20230921230637045

Simplified diagram made by blogger

image-20230922001841775

TERMINATED:

Once the thread PCB in the kernel dies, the t object in the code is useless. The
life cycle of objects in Java is not exactly the same as the threads in the system kernel.
When the kernel thread is released, there is no guarantee that the t object in the Java code will be used. The object is also released immediately
. Therefore, there is bound to be a situation where the kernel PCB is gone, but t in the code is still in this situation.
At this time, it is necessary to mark the t object as "invalid" through a specific state.

It cannot be restarted. A thread can only be started once!!
~~ A variable/object generally has only one purpose (conventional rule)

Sample code:

public class ThreadDemo11 {
    
    
    public static void main(String[] args) throws InterruptedException {
    
    
        Thread t = new Thread(()->{
    
    
            for (int i = 0; i < 1000000; i++) {
    
    
                // 这个循环体什么都不做
            }
        });

        // 启动之前, 获取 t 的状态, 就是 NEW 状态
        System.out.println("start 之前: "+t.getState());

        t.start();
        System.out.println("线程 t 执行中的状态: "+ t.getState());
        t.join();

        // 线程执行完毕之后, 就是 TERMINATED 状态
        System.out.println("线程 t 结束之后: "+ t.getState());
    }
}

operation result:

image-20230922092731551

The reason why RUNNABLE can be seen here is mainly because there is no method such as sleep written in the current thread run. The
current status obtained depends entirely on the scheduling operation of the system.

What exactly is the meaning of multithreading?

Multithreading

Multi-threading plays a very important role in such CPU-intensive tasks. It can make full use of the multi-core resources of the CPU
to speed up the running efficiency of the program.

Multithreading is also very useful in IO-intensive tasks.
~~ When we use smartphones, we sometimes encounter the interface prompt of "Program Not Responding" (for example, when opening QQ Music). The
program performs some time-consuming IO operations (for example, QQ Music needs to load data files when starting up. It involves a large number of hard disk reading operations), blocking the response of the interface. In this case, using multi-threading can also be effectively improved (one thread is responsible for IO, and the other thread is used to respond to user operations).

Single thread writing:

public class ThreadDemo12 {
    
    
    public static void main(String[] args) {
    
    
        // 假设当前有两个变量, 需要把两个变量各自自增 100亿次. => 典型的 CPU 密集型的场景
        // 可以一个线程, 先针对 a 自增, 然后再针对 b 自增
        // 还可以两个线程, 分别是 a 和 b 自增
        serial();
    }
    // serial (串行)  ~~ 串行执行, 一个线程完成
    public static void serial() {
    
    
        // 为了衡量代码的执行速度, 加上个计时的操作
        // currentTimeMillis 获取到当前系统的 ms 级时间戳
        long beg = System.currentTimeMillis();

        long a = 0;
        for (long i = 0; i < 100_0000_0000L; i++) {
    
    
            a++;
        }
        long b = 0;
        for (long j = 0; j < 100_0000_0000L; j++) {
    
    
            b++;
        }

        long end = System.currentTimeMillis();
        System.out.println("执行时间: " + (end - beg) + " ms");
    }
}

image-20230922130954861

The running results of single-threaded writing:

image-20230922131048182

Note: Just like this kind of code that measures execution time, it is not a bad thing to let it run longer. The longer it runs, the smaller the error will be. (
Thread scheduling itself also has time overhead) The greater the amount of computing tasks, the better the thread scheduling. The overhead is not obvious in comparison and can therefore be ignored.


Multi-threaded writing:

package thread;

/**
 * Created with IntelliJ IDEA.
 * Description:
 * User: fly(逐梦者)
 * Date: 2023-09-22
 * Time: 11:45
 */


// 通过这个线程来演示, 多线程和单线程相比, 效率的提升
public class ThreadDemo12 {
    
    
    public static void main(String[] args) {
    
    
        // 假设当前有两个变量, 需要把两个变量各自自增 100亿次. => 典型的 CPU 密集型的场景
        // 可以一个线程, 先针对 a 自增, 然后再针对 b 自增
        // 还可以两个线程, 分别是 a 和 b 自增
        //serial();
        concurrency();
    }
    // concurrency(并发性)
    public static void concurrency() {
    
    
        // 使用两个线程分别完成自增.
        Thread t1 = new Thread(() -> {
    
    
            long a = 0;
            for (long i = 0; i < 100_0000_0000L; i++) {
    
    
                a++;
            }
        });
        Thread t2 = new Thread(()->{
    
    
            long b = 0;
            for (long j = 0; j<100_0000_0000L;j++){
    
    
                b++;
            }
        });
        // 开始计时
        long beg = System.currentTimeMillis();
        t1.start();
        t2.start();
        try {
    
    
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
    
    
            e.printStackTrace();
        }
        // 结束计时
        long end = System.currentTimeMillis();
        System.out.println("执行时间: " + (end - beg) + " ms");
    }
}

image-20230922160757255

The running results of multi-threaded writing method:

image-20230922160919930

Code execution sequence:

The main thread first calls t1.start.
When starting t1 and starting to calculate t1, main calls t2.start.
When starting t2, t1 still continues to calculate. At the same time, the main thread enters t1.join.
At this time, main blocks and waits. T1 and t2 continue to execute.
When t1 is completed, the main thread returns from t1.join, then enters t2.join, and waits again.
When t2 is completed, main returns from t2.join, continues to perform timing operations and prints execution. Time.
~~ It is possible that t2 ends before t1, but it has no impact on the program result.
t1.join still waits normally. When t2.join is executed, it returns immediately and no longer waits.

Two threads are used for concurrent execution here, and the time is indeed shortened significantly (4916ms -> 2491ms)

Why is it faster to use multithreading?

Multi-threading can more fully utilize the resources of multi-core CPU~~

But why isn’t it just shortened by half?

(1) t1 and t2 are not necessarily executed on two CPUs.
They may be executed in parallel or concurrently.
In fact, t1 and t2 will undergo many times of scheduling during the execution process. .Some
of these schedules are executed concurrently (on one core), and some are executed in parallel (on exactly two cores).
(2) Thread scheduling itself also consumes time.

Although the shortening is not 50%, it is still obvious and still meaningful!!

Recommended books to learn multi-threading:

<<The art of Java concurrent programming>>, <<Java multi-threading core technology>>

Common development directions:

1. Back-end development
2. Front-end development
3. Client development
4. Test development
5. Operation and maintenance development
6. Algorithm engineer (strategy development)
7. Game development
...

Summary of the current learning phase of multi-threading

Summary of multi-threaded learning stages

Guess you like

Origin blog.csdn.net/m0_73740682/article/details/133178144