The subject read this knowledge of concurrent interviews, and there is no more failure in the interview

content

What are threads and processes?

What is a process?

What is a thread?

Please briefly describe the relationship between threads and processes, their differences, advantages and disadvantages?

Illustrate the relationship between processes and threads

Why is the program counter private?

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

A simple sentence to understand the heap and method area

What is the difference between concurrency and parallelism?

Why use multithreading?

What are the possible problems with using multithreading?

Talk about the life cycle and state of the thread?

What is context switching?

What is thread deadlock? How to avoid deadlock?

Recognize thread deadlock

How to prevent and avoid thread deadlock?

Talk about the difference and commonalities between the sleep() method and the wait() method?

Why does the run() method execute when we call the start() method, and why can't we call the run() method directly?

 

What are threads and processes?

What is a process?

A process is an execution process of a program and is the basic unit of a system running a program, so the process is dynamic. Running a program in the system is a process from creation, operation to death of a process.

In Java, when we start the main function, we actually start a JVM process, and the thread where the main function is located is a thread in this process, also called the main thread.

As shown in the figure below, by looking at the task manager in windows, we can clearly see the currently running process of the window (the running of the .exe file).

What is a thread?

A thread is similar to a process, but a thread is a smaller unit of execution than a process. A process can spawn multiple threads during its execution. Different from a process, multiple threads of the same type share the process's heap and method area resources, but each thread has its own program counter , virtual machine stack and local method stack , so the system is generating a thread, or between each thread. When switching between tasks, the burden is much smaller than that of processes, and because of this, threads are also called lightweight processes.

Java programs are inherently multithreaded programs. We can use JMX to see what threads a common Java program has. The code is as follows.

public class MultiThread {
    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());
        }
    }
}

The output of the above program is as follows (the output content may be different, don't worry too much about the role of each thread below, just know that the main thread executes the main method):

[5] Attach Listener //添加事件
[4] Signal Dispatcher // 分发处理给 JVM 信号的线程
[3] Finalizer //调用对象 finalize 方法的线程
[2] Reference Handler //清除 reference 线程
[1] main //main 线程,程序入口Copy to clipboardErrorCopied

It can be seen from the above output that the running of a Java program is that the main thread and multiple other threads run at the same time .

Please briefly describe the relationship between threads and processes, their differences, advantages and disadvantages?

The relationship between processes and threads from the perspective of the JVM

Illustrate the relationship between processes and threads

The following figure is the Java memory area. Through the following figure, we will talk about the relationship between threads and processes from the perspective of the JVM.

As can be seen from the above figure: there can be multiple threads in a process, and multiple threads share the heap and method area (metaspace after JDK1.8)** resources of the process, but each thread has its own program counter , virtual Machine stack** and  native method stack .

Summary: A  thread is a process divided into smaller units of operation. The biggest difference between threads and processes is that basically each process is independent, while each thread is not necessarily, because threads in the same process are very likely to affect each other. Thread execution overhead is small, but it is not conducive to resource management and protection; while the process is the opposite.

The following is an extension of this knowledge point!

Let's think about this question: why are the program counter , virtual machine stack and native method stack thread private? Why are the heap and method areas shared by threads?

Why is the program counter private?

The program counter has two main functions:

  1. The bytecode interpreter reads the instructions in sequence by changing the program counter, so as to realize the flow control of the code, such as: sequential execution, selection, loop, exception handling.
  2. 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 can 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, and only when the Java code is executed is the program counter records the address of the next instruction.

Therefore, the program counter is private mainly to restore the correct execution position after thread switching .

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

  • Virtual machine stack:  Each Java method will create a stack frame to store information such as local variable table, operand stack, constant pool reference, etc. The process from method invocation to completion of execution corresponds to the process of stacking and popping a stack frame in the Java virtual machine stack.
  • Local method stack:  It is very similar to the role played by the virtual machine stack, the difference is: the  virtual machine stack serves for 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.

Therefore, in order to ensure that the local variables in the thread are not accessed by other threads , the virtual machine stack and the native method stack are thread-private.

A simple sentence to understand the heap and method area

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

What is the difference between concurrency and parallelism?

  • Concurrency:  Multiple tasks are executing in the same time period (not necessarily executed at the same time per unit time);
  • Parallelism:  Multiple tasks are executed simultaneously in a unit of time.

Why use multithreading?

First in general:

  • 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 CPUs means that multiple threads can run concurrently, 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 developing high-concurrency systems. The use of multi-threading mechanisms can greatly improve the overall concurrency of the system. capability and performance.

Then go deep into the bottom layer of the computer to explore:

  • Single-core era : In the single-core era, multithreading is mainly to improve the efficiency of single-process utilization of CPU and IO system. Assuming that only one Java process is running, when we request IO, if there is only one thread in the Java process, this thread is blocked by IO and the entire process is blocked. Only one CPU and IO device is running, so it can be simply said that the overall efficiency of the system is only 50%. When using multithreading, one thread is blocked by IO, and other threads can continue to use the CPU. Thus, the overall efficiency of the Java process using system resources is improved.
  • Multi-core era : Multi-threading in the multi-core era is mainly to improve the ability of processes to utilize multi-core CPUs. For example: if we want to calculate a complex task and we only use one thread, no matter how many CPU cores the system has, only one CPU core will be used. When multiple threads are created, these threads can be mapped to multiple underlying CPUs for execution. Under the condition that multiple threads in a task do not compete for resources, the efficiency of task execution will be significantly improved, which is approximately equal to (when a single core is used) execution time/number of CPU cores).

What are the possible problems with using multithreading?

The purpose of concurrent programming is to improve the execution efficiency of the program and increase the running speed of the program, but concurrent programming does not always improve the running speed of the program, and concurrent programming may encounter many problems, such as: memory leaks, deadlocks, threads Not safe and so on.

Talk about the life cycle and state of the thread?

A Java thread may only be in one of the following 6 different states at a given moment in its running life cycle (see section 4.1.4 of the source "The Art of Java Concurrent Programming").

Threads are not fixed in a certain state during the life cycle, but switch between different states as the code executes. The state transition of Java threads is shown in the following figure (the source of the picture is "The Art of Java Concurrent Programming", Section 4.1.4):

Correction (from issue736 ): In the transition from wait to runnable state in the original image, joinit is actually a Threadclass method, but it is written here Object.

As can be seen from the above figure: after the thread is created, it will be in the  NEW (new)start() state, and  it will start running after   calling  the method, and the thread will be in the READY (runnable)  state at this time. A thread in the runnable state is in the  RUNNING  state after it has obtained a CPU time slice (timeslice).

In the operating system, threads have READY and RUNNING states, while at the JVM level, only the RUNNABLE state can be seen (Source: HowToDoInJava : Java Thread Life Cycle and Thread States ), so the Java system generally refers to these two states as  RUNNABLE ( running)  status.

Why doesn't the JVM distinguish between these two states?  (Excerpt from: How does java thread run in a sixth state? - Dawell's answer  ) The current time -sharing multi- task (multi-task) operating system architecture usually uses the so-called " time quantum or time slice)" method for preemptive round-robin scheduling. This time slice is usually very small, and a thread can only run on the CPU for a maximum of 10-20ms at a time (in the running state at this time), that is, it is only about 0.01 seconds. To be switched off and put at the end of the dispatch queue to wait for rescheduling. (ie back to ready state). With threads switching so fast, it makes little sense to distinguish between the two states.

When the thread executes the  wait()method, the thread enters the  WAITING  state. The thread entering the waiting state needs to rely on the notification of other threads to return to the running state, and the  TIMED_WAITING (timeout waiting)  state is equivalent to adding a timeout limit on the basis of the waiting state. For example,  a Java thread can be placed in TIMED_WAITING by a sleep(long millis)method or  method. wait(long millis)condition. The Java thread will return to the RUNNABLE state when the timeout period expires. When a thread calls a synchronized method, the thread will enter the BLOCKED state without acquiring the lock   . run()The thread will enter the  TERMINATED state after executing the Runnable method  .

Related reading: Picking Mistakes | Three Mistakes About Thread State in The Art of Java Concurrent Programming  .

What is context switching?

Threads have their own operating conditions and states (also called contexts) during execution, such as the program counter and stack information mentioned above. When the following conditions occur, the thread will exit from the CPU-occupied state.

  • Actively give up the CPU, such as calling  sleep()wait() etc.
  • The time slice runs out, because the operating system wants to prevent a thread or process from occupying the CPU for a long time and cause other threads or processes to starve to death.
  • A blocking type of system interrupt is called, such as requesting IO, and the thread is blocked.
  • terminated or terminated

The first three of these will have thread switching. Thread switching means that the context of the current thread needs to be saved and left to restore the scene when the thread occupies the CPU next time. and loads the next thread context that will consume the CPU. This is called a  context switch .

Context switching is a basic function of modern operating systems, because it needs to save information and restore information every time, which will occupy system resources such as CPU and memory for processing, which means that there will be a certain loss of efficiency. Frequent switching will cause overall damage. low efficiency.

What is thread deadlock? How to avoid deadlock?

Recognize thread deadlock

A thread deadlock describes a situation where multiple threads are blocked at the same time, one or all of them waiting for a resource to be released. Since the thread is blocked indefinitely, it is impossible for the program to terminate normally.

As shown in the figure below, thread A holds resource 2 and thread B holds resource 1. They both want to apply for each other's resources at the same time, so these two threads will wait for each other and enter a deadlock state.

The following is an example to illustrate thread deadlock. The code simulates the deadlock situation in the above figure (the code comes from "The Beauty of Concurrent Programming"):

public class DeadLockDemo {
    private static Object resource1 = new Object();//资源 1
    private static Object resource2 = new Object();//资源 2

    public static void main(String[] args) {
        new Thread(() -> {
            synchronized (resource1) {
                System.out.println(Thread.currentThread() + "get resource1");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread() + "waiting get resource2");
                synchronized (resource2) {
                    System.out.println(Thread.currentThread() + "get resource2");
                }
            }
        }, "线程 1").start();

        new Thread(() -> {
            synchronized (resource2) {
                System.out.println(Thread.currentThread() + "get resource2");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread() + "waiting get resource1");
                synchronized (resource1) {
                    System.out.println(Thread.currentThread() + "get resource1");
                }
            }
        }, "线程 2").start();
    }
}Copy to clipboardErrorCopied

Output

Thread[线程 1,5,main]get resource1
Thread[线程 2,5,main]get resource2
Thread[线程 1,5,main]waiting get resource2
Thread[线程 2,5,main]waiting get resource1Copy to clipboardErrorCopied

Thread A by  synchronized (resource1) acquiring  resource1 the monitor lock, and then by Thread.sleep(1000);letting thread A sleep for 1s in order for thread B to get executed and then acquire the monitor lock on resource2. After the sleep of thread A and thread B is over, they both start to request to acquire each other's resources, and then the two threads will fall into the state of waiting for each other, which will result in deadlock. The above example meets the four necessary conditions for a deadlock to occur.

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

  1. Mutual exclusion condition: The resource is occupied by only one thread at any time.
  2. Request and hold condition: When a process is blocked by requesting a resource, it will hold on to the obtained resource.
  3. No deprivation condition: The resources obtained by a thread cannot be forcibly deprived by other threads before they are used up, and the resources are released only after they are used up.
  4. Circular waiting condition: A cyclic waiting resource relationship is formed between several processes.

How to prevent and avoid thread deadlock?

How to prevent deadlock?  The necessary conditions for breaking the deadlock can be:

  1. Break Request and Hold  : Request all resources at once.
  2. Destruction of the non-preemption condition  : When a thread that occupies some resources further applies for other resources, if it cannot apply for it, it can actively release the resources it occupies.
  3. Destruction of circular waiting conditions  : Prevented by applying for resources in order. Apply for resources in a certain order, and release resources in reverse order. Breaks the cyclic wait condition.

How to avoid deadlock?

To avoid deadlock is to use an algorithm (such as the banker's algorithm) to calculate and evaluate the resource allocation during resource allocation, so that it can enter a safe state.

The safe state  means that the system can allocate the required resources to each thread according to a certain thread advancement order (P1, P2, P3...Pn), until the maximum demand for resources of each thread is met, so that each thread The thread can be completed successfully. The <P1, P2, P3...Pn> sequence is called a security sequence.

We modify the code of thread 2 to the following so that no deadlock occurs.

        new Thread(() -> {
            synchronized (resource1) {
                System.out.println(Thread.currentThread() + "get resource1");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread() + "waiting get resource2");
                synchronized (resource2) {
                    System.out.println(Thread.currentThread() + "get resource2");
                }
            }
        }, "线程 2").start();Copy to clipboardErrorCopied

Output

Thread[线程 1,5,main]get resource1
Thread[线程 1,5,main]waiting get resource2
Thread[线程 1,5,main]get resource2
Thread[线程 2,5,main]get resource1
Thread[线程 2,5,main]waiting get resource2
Thread[线程 2,5,main]get resource2

Process finished with exit code 0

Let's analyze why the above code avoids the occurrence of deadlock?

Thread 1 first obtains the monitor lock of resource1, then thread 2 cannot obtain it. Then thread 1 acquires the monitor lock of resource2, which can be acquired. Then thread 1 releases the occupancy of the monitor locks of resource1 and resource2, and thread 2 can execute it after obtaining it. This breaks the breaking loop wait condition, thus avoiding deadlock.

Talk about the difference and commonalities between the sleep() method and the wait() method?

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

Why does the run() method execute when we call the start() method, and why can't we call the run() method directly?

This is another very classic Java multithreading interview question, and one that is often asked in interviews. It's very simple, but many people can't answer it!

new a Thread, the thread enters the new state. Calling  start()the method will start a thread and make the thread enter the ready state. When the time slice is allocated, it can start running. start() The corresponding preparation work for the thread is performed, and then the content of the method is automatically executed  run() , which is true multi-threaded work. However, directly executing the  run() method will  execute the run() method as an ordinary method under the main thread, and will not execute it in a certain thread, so this is not multi-threaded work.

Summary: Calling  start() the method can start the thread and make the thread enter the ready state. If the  run() method is directly executed, it will not be executed in a multi-threaded manner.

Guess you like

Origin blog.csdn.net/weixin_44302240/article/details/123702942