"Java concurrent programming" common basic problems

Process and thread?

process?

  • A process is an execution process of a program, the basic unit of the system to run a program , and the process is dynamic.
  • The system running a program is the process of a process from creation, operation to death.

In Java, when the main function is started, a JVM process is actually started , and the thread where the main function is located is the main thread of the process.

Thread?

A thread is a process than a smaller unit of execution.

A process generates multiple threads during its execution, and multiple threads of the same kind share the process's heap and method area resources . Each thread has its own program counter, virtual machine stack, and local method stack.

When the system generates a thread or switches work between threads, the burden is much smaller than that of the process , so the thread is also called a lightweight process.

Java programs are inherently multi-threaded programs, you can check it through JMX:

public class Main {

    public static void main(String[] args) {
        // 获取 Java 线程管理 MXBean
        ThreadMXBean threadMXBean = ManagementFactory.getThreadMXBean();
        // 不需要获取同步的 monitor 和 synchronizer 信息,仅获取线程和线程堆栈信息
        ThreadInfo[] threadInfos = threadMXBean.dumpAllThreads(false,false);
        // 遍历线程信息,仅打印线程 ID 和线程名称信息 和 线程状态
        for (ThreadInfo threadInfo : threadInfos) {
            System.out.println("[" + threadInfo.getThreadId() + "]" + threadInfo.getThreadName() + "->" + threadInfo.getThreadState());
        }
    }
    
}

The output is as follows:

[6]Monitor Ctrl-Break->RUNNABLE //这是IDEA特有的监控线程
[5]Attach Listener->RUNNABLE //添加事件
[4]Signal Dispatcher->RUNNABLE  // 分发处理给 JVM 信号的线程
[3]Finalizer->WAITING    //清除 reference 线程
[2]Reference Handler->WAITING  //清除 reference 线程
[1]main->RUNNABLE //main线程,程序入口

A Java program has to run with the main thread and multiple threads running at the same time.

Concurrency and parallelism?

  • Concurrency:  multiple tasks are executed at the same time period (not necessarily executed at the same time per unit time);
  • Parallel:  Multiple tasks are executed simultaneously in unit time.

 

Talk about the relationship between process and thread from the perspective of JVM

A process can have multiple threads, and multiple threads share the resources of the process's heap and method area [metaspace after JDK1.8], but each thread has its own independent program counter, virtual machine stack, and local method stack .

Can draw:

  • A thread is a smaller operating unit divided into a process. The biggest difference between a thread and a process is that each process is basically independent, but each thread is not necessarily. The threads in the same process are likely to affect each other.
  • The thread execution overhead is small, but it is not conducive to resource management and protection, while the process is just the opposite.

Why is the program counter private?

The role of the program counter:

  • The bytecode interpreter reads instructions sequentially by changing the program counter, thereby realizing code flow control, such as sequential execution, selection, looping, and exception handling.
  • In the case of multithreading, the program counter is used to record the position of the current thread execution, so that when the thread is switched back, it is possible to know where the thread ran last time .

It should be noted that if the native method is executed, the program counter records the undefined address. Only when the Java code is executed, the program counter records the address of the next instruction.

Summary: The private program counter is mainly used to restore the correct execution position after thread switching .

Why are the virtual machine stack and local method stack private?

  • Virtual machine stack: When  each Java method is executed, a stack frame is created to store the local variable table, operand stack, constant pool reference and other information. The process from method call to completion of execution corresponds to the process of pushing and popping a stack frame in the Java virtual machine stack.
  • Native method stack:  The role played by the virtual machine stack is very similar. The difference is: the  virtual machine stack serves the virtual machine to execute Java methods (that is, bytecode), while the local method stack serves the native methods used by the virtual machine .  The HotSpot virtual machine and the Java virtual machine stack are combined into one.

Summary: The virtual machine stack and the local method stack are private to ensure that the local variables in the thread are not accessed by other threads .

A simple sentence to understand the heap and method area

The heap and method area are resources shared by all threads. The heap is the largest piece of memory in the process. It is mainly used to store newly created objects [almost all objects are allocated memory here], and the method area is mainly used to store loaded Data such as class information, constants, static variables, and code compiled by the just-in-time compiler.

Why use multithreading? What's the use of multithreading?

From the general on it:

  • From the bottom of the computer: a thread can be compared to a lightweight process, the smallest unit of program execution, and the cost of switching and scheduling between threads is far less than that of a process . In addition, the era of multi-core CPU means that multiple threads can run at the same time , which reduces the overhead of thread context switching.
  • From the perspective of contemporary Internet development trends: the current system requires millions or even tens of millions of concurrency at every turn, and multi-threaded concurrent programming is the basis for the development of high-concurrency systems. The use of multi-threaded mechanisms can greatly improve the overall concurrency of the system. Ability and performance .

Go to the bottom of the computer to discuss:

  • Single-core era: In the single-core era, multithreading is mainly to improve the comprehensive utilization of CPU and IO devices. When there is only one thread, it will cause the IO device to be idle when the CPU calculates; when performing IO operations, the CPU is idle. We can simply say that the utilization of both is currently around 50%. But when there are two threads, it is different. When one thread performs CPU calculations, the other thread can perform IO operations, so that the utilization of the two can reach 100% under ideal conditions.
  • Multi-core era: Multi-threading in the multi-core era is mainly to improve CPU utilization. If we want to calculate a complex task and we only use one thread, only one CPU core of the CPU will be used, and creating multiple threads will allow multiple CPU cores to be used, thus increasing the utilization of the CPU .

What problems might be caused by using multithreading?

  • Memory leak
  • Deadlock
  • Thread unsafe

Recommended viewing: Portal

The life cycle and state of the thread?

Six states

Thread state explanation NEW The thread state that has not been started, that is, the thread is created, and the start method has not been called. RUNNABLE Ready state (call start, waiting for scheduling) + Running BLOCKED while waiting for the monitor lock , the thread in the blocked state WAITING waiting state is waiting for another A thread performs a specific operation (such as notify) TIMED_WAITING a waiting state with a specified waiting time TERMINATED thread finishes execution, termination state

State switching

 

Note: The join method is a method under the Thread class. It is written as Object in the figure, and should be changed to Thread.join.

After the thread is created, it will be in the NEW (new)  state, and it will  start running after calling the start() method. The thread is now in the  READY (runnable)  state. The thread in the runnable state is in the RUNNING  state after obtaining the CPU time slice (timeslice)  .

When the thread executes the wait() method, the thread enters the  WAITING (waiting)  state. A thread that enters the waiting state needs to rely on notifications from other threads to return to the running state, and the  TIME_WAITING  state is equivalent to adding a timeout limit to the waiting state, such as through the sleep (long millis) method or wait (long millis) method can put the Java thread in the TIMED WAITING state. When the timeout expires, the Java thread will return to the RUNNABLE state. When the thread calls the synchronization method, the thread will enter the BLOCKED (blocked)  state without acquiring the lock  . The thread will enter the TERMINATED (terminated)  state after executing the run() method of Runnable  .

What is context switching?

In multi-threaded programming, the number of threads is generally greater than the number of CPU cores, and a CPU core can only be used by one thread at any time . In order to enable these threads to be executed effectively, the CPU adopts a strategy for each thread The form of allocating time slices and rotating. When the time slice of a thread is used up, it will be in the ready state again for other threads to use. This process is a context switch.

In a nutshell: the current task will save its state before switching to another task after executing the CPU time slice, so that the state of this task can be loaded again when switching back to this task next time. The process from saving to reloading a task is a context switch .

Context switching is usually computationally intensive . In other words, it requires a considerable amount of processor time. In dozens or hundreds of switchings per second, each switching takes nanoseconds. Therefore, context switching means consuming a lot of CPU time for the system. In fact, it may be the most time-consuming operation in the operating system.

Compared with other operating systems (including other Unix-like systems), Linux has many advantages, one of which is that it consumes very little time for context switching and mode switching.

What is thread deadlock and how to avoid deadlock?

Multiple threads are blocked at the same time, one or all of them are waiting for a resource to be released.

Friends who have studied operating systems know that the following four conditions must be met to produce a deadlock:

  1. Mutually exclusive condition : The resource is occupied by only one thread at any time.
  2. Request and hold conditions : When a process is blocked by requesting resources, it keeps the acquired resources.
  3. Non-deprivation conditions : The resources that a thread has acquired cannot be forcibly deprived by other threads before it is used up, and the resources are released only after they are used up.
  4. Circulating waiting condition : A kind of cyclic waiting resource relationship is formed between several processes.

How to avoid thread deadlock?

I mentioned the four necessary conditions for deadlock. In order to avoid deadlock, we only need to destroy one of the four conditions for deadlock. Now let’s analyze one by one:

  1. Destroy the mutually exclusive condition  : We have no way to destroy this condition, because our users originally wanted them to be mutually exclusive (critical resources require exclusive access).
  2. Destruction request and retention conditions  : apply for all resources at once.
  3. Destruction and non-deprivation conditions  : When a thread occupying some resources further applies for other resources, if the application fails, it can actively release the resources it occupies.
  4. Destroy the cycle waiting conditions  : prevent by applying for resources on demand. Apply for resources in a certain order, and release resources in reverse order. Destroy the loop waiting condition.

Talk about the difference and commonality between sleep() and wait() methods?

  • The two main differences are that the sleep method does not release the lock, while the wait() method releases the lock.
  • Both can suspend the execution of threads.
  • Wait is usually used for interaction/communication between threads, and sleep is usually used to suspend execution.
  • After the wait() method is called, the thread will not automatically wake up, and other threads need to call the notify() or notifyAll() method on the same object. After the sleep() method is executed, the thread will automatically wake up. Or you can use wait(long timeout) to automatically wake up the thread after timeout.

Why do we execute the run() method when we call the start() method, why can’t we call the run() method directly?

This is another very classic java multi-threaded interview question, and it is often asked during the interview. It's simple, but many people will not be able to answer!

new a Thread, the thread enters a new state; calling the start() method will start a thread and make the thread enter the ready state, and it can start running when the time slice is allocated. start() will perform the corresponding preparation work of the thread, and then automatically execute the content of the run() method, which is truly multi-threaded work. By directly executing the run() method, the run method will be executed as a normal method under the main thread, and it will not be executed in a thread, so this is not a multithreaded work.

Summary: Call the start method to start the thread and make the thread enter the ready state, while the run method is just an ordinary method call of thread, or it is executed in the main thread.

If you think this article is helpful to you, you can like it and follow it to support it, or you can follow my public account, there are more technical dry goods articles and related information sharing, everyone can learn and progress together!

 

Guess you like

Origin blog.csdn.net/weixin_50205273/article/details/108681994