Summary of 40 Java multithreading issues and 40 Java Multithreading
Preface
I personally think that the more you learn, the more complicated and complex the knowledge, the more you need to make a profound summary so that you can remember deeply and turn your knowledge into your own. This article mainly summarizes the problem of multithreading, so it lists the problem of 40 multithreading.
Some of these multithreading problems come from major websites and some from their own ideas. There may be some questions online, some answers to some questions, or some netizens may have read them, however, the focus of this article is that all questions will be answered according to your own understanding and won't go to the online answers. Therefore, some questions may be wrong and I hope you will not give any advice.
40 problem summary
1. What is the use of multithreading?
One question that may seem to many people to be bullshit: I can use multiple threads, but what is the purpose? In my opinion, this answer is even more nonsense. The so-called "knowing what it is, knowing why it is" will use "but" knowing why ", and" why it is used ", it can be said that a knowledge point can be used freely only when it reaches the level of "knowing what actually knows why. OK. Let's talk about my views on this issue:
(1) give full play to the advantages of multi-core CPU
With the development of the industry, the current laptops, desktops, and even commercial application servers are at least dual-core, and 4-core, 8-core, or 16-core are also quite common, if it is a single-threaded program, 50% is wasted on the dual-core CPU and 75% is wasted on the 4-core CPU. The so-called "multi-thread" on a single-core CPU is a fake multi-thread. At the same time, the processor only processes a piece of logic, but the switching between threads is faster, it looks like multiple threads are running at the same time. Multi-thread on multi-core CPU is the real multi-thread. It allows you to operate multiple segments of logic at the same time. multi-thread can truly leverage the advantages of multi-core CPU to make full use of the CPU.
(2) prevent blocking
From the perspective of program running efficiency, a single-core CPU not only does not take advantage of multithreading, but rather runs multiple threads on a single-core CPU, resulting in thread context switching, reducing the overall program efficiency. However, we still need to apply multithreading to single-core CPUs to prevent blocking. Imagine if a single-core CPU uses a single thread, as long as this thread is blocked, for example, reading a data remotely, the peer has not returned yet and no timeout time is set, then your entire program stops running before the data is returned. Multithreading can prevent this problem. multiple threads run at the same time. Even if the code execution of one thread blocks reading data, it will not affect the execution of other tasks.
(3) Easy Modeling
This is another advantage. Assume that there is A large task A, single-Thread Programming, so there are A lot of considerations, it is more difficult to establish the entire program model. However, if this large task A is divided into several small tasks, such as Task B, task C, and task D, program models are created respectively, and these tasks are run separately through multiple threads, that's much simpler.
2. Thread Creation Method
There are two common problems:
(1) inherit the Thread class
(2) Implement the Runnable interface
As for which one is better, it must be better than the latter, because the method of implementing interfaces is more flexible than the method of inheriting classes, and the coupling between programs can also be reduced, interface-Oriented Programming is also the core of the six principles of design patterns.
3. Differences between the start () method and the run () method
Only when the start () method is called can the code in the run () method of different threads be executed alternately. If you only call the run () method, the code is still executed synchronously. After all the code in the run () method of a thread is executed, another thread can execute the code in its run () method.
4. Differences between the Runnable and Callable Interfaces
This is a bit of a deep problem. It also shows the breadth of knowledge learned by a Java programmer.
The Return Value of the run () method in the Runnable interface is void, which only executes the code in the run () method purely () methods return values and are generic. They can be used with Future and FutureTask to obtain asynchronous execution results.
This is actually a very useful feature, because one of the important reasons why multithreading is more difficult and more complex than a single thread is that multithreading is full of unknowns. is a thread executed? How long has a thread been executed? Has the expected data been assigned a value during execution of a thread? What we can do is wait for the execution of this multi-threaded task to complete. However, Callable + Future/FutureTask can obtain the results of multi-thread running. It is really useful to cancel the tasks of this thread when the required data is not obtained after waiting for too long.
5. Differences between CyclicBarrier and CountDownLatch
The two classes, both of which look a bit like java. util. concurrent, can be used to indicate that the code runs to a certain point. The difference between the two is:
(1) After a thread of javasicbarrier runs to a certain point, the thread stops running until all threads reach this point, and all threads re-run. CountDownLatch is not, after a thread runs to a certain point, it only gives a value of-1. The thread continues to run.
(2) CyclicBarrier can only invoke one task. CountDownLatch can call multiple tasks.
(3) CyclicBarrier can be reused. CountDownLatch cannot be reused. If the Count value is 0, the CountDownLatch cannot be reused.
6. Role of the Volatile keyword
A very important issue is that every Java programmer who learns and applies multithreading must master it. The prerequisite for understanding the volatile keyword is to understand the Java memory model. Here we will not talk about the Java memory model. For details, refer to the 31st point. The volatile keyword has two main functions:
(1) multithreading mainly centers around the visibility and atomicity. Variables modified with the volatile keyword ensure the visibility between multiple threads, that is, the volatile variable is read each time, it must be the latest data
(2) The underlying code execution is not as simple as the Java program, which is an advanced language we see, it runs Java code-> bytecode-> C/C ++ code based on bytecode-> C/C ++ code is compiled into assembly language-> and hardware Circuit interaction, in reality, in order to obtain better performance, JVM may re-sort the commands, and unexpected problems may occur in multiple threads. Using volatile reduces the efficiency of code execution.
From a practical point of view, volatile plays an important role in combination with CAS to ensure atomicity. For details, see classes in the java. util. concurrent. atomic package, such as AtomicInteger.
7. What is thread security?
It is also a theoretical question. There are many different kinds of answers. I give the best explanations one by one: if your code is executed in multiple threads and in a single thread, it will always get the same result, then your code is thread-safe.
It is worth mentioning that there are several levels of thread security:
(1) immutable
All classes such as String, Integer, and Long are final classes. No thread can change their values unless a new one is created, therefore, these Immutable objects can be directly used in a multi-threaded environment without any synchronization means.
(2) Absolute thread security
No matter what the runtime environment is, the caller does not need any additional synchronization measures. To do this, it usually requires a lot of extra costs. Java marks itself as a thread-safe class. In fact, most of them are not thread-safe, but absolutely thread-safe classes, in Java, for example, CopyOnWriteArrayList and CopyOnWriteArraySet
(3) Relative thread security
Relative thread security is what we usually call thread security. Like a Vector, the add and remove methods are atomic operations and will not be interrupted, but they are also limited to this, if a thread traverses a Vector and adds the Vector at the same time, ConcurrentModificationException will occur in 99%, that is, the fail-fast mechanism.
(4) thread non-security
There is nothing to say about this. ArrayList, rule list, And HashMap are all non-thread-safe classes.
8. How to obtain the thread dump file in Java
Thread dump is the best way to solve problems such as endless loops, deadlocks, congestion, and slow page opening. The so-called thread dump is the thread stack. There are two steps to obtain the thread Stack:
(1) obtain the thread pid. You can use the jps command and ps-ef | grep java in Linux.
(2) print the thread stack. You can use the jstack pid command and kill-3 pid in Linux.
In addition, the Thread class provides a getStackTrace () method to obtain the Thread stack. This is an instance method, so this method is bound to a specific thread instance. Each time you obtain the stack that is currently running by a specific thread,
9. What if a running exception occurs to a thread?
If the exception is not captured, the thread stops running. Another important point is that if the thread holds the monitor of an object, the object monitor will be released immediately.
10. How to share data between two threads
You can share objects between threads, and call and wait through wait/notify/notifyAll, await/signal/signalAll, for example, BlockingQueue, a blocking queue, is designed to share data between threads.
11. What are the differences between sleep and wait?
The sleep method and wait method can be used to discard the CPU for a certain period of time. The difference is that if the thread holds the monitor of an object, the sleep method will not discard the monitor of this object, the wait method will discard the monitor of this object
12. What is the role of the producer-consumer model?
This problem is theoretical, but important:
(1) The efficiency of the entire system is improved by balancing the producer's production capacity and consumer consumption capacity. This is the most important role of the producer consumer model.
(2) decoupling: This is a function attached to the producer and consumer model. Decoupling means that there are fewer connections between producers and consumers. The fewer connections, the more independent they can develop without mutual restrictions.
13. What is the use of ThreadLocal?
To put it simply, ThreadLocal is a method of changing the time of space. It maintains a ThreadLocal implemented by the open address method in each Thread. threadLocalMap isolates data and does not share data. Naturally, there is no thread security problem.
14. Why is the wait () method and notify ()/notifyAll () method called in the synchronization block?
This is mandatory by JDK. The wait () method and the notify ()/policyall () method must obtain the object lock before calling.
15. What is the difference between the wait () method and the notify ()/notifyAll () method when dropping the object monitor?
The difference between the wait () method and the notify ()/notifyAll () method when dropping the object monitor is that the wait () method immediately releases the object monitor, notify ()/notifyAll () the object monitor will be discarded only after the remaining code of the thread is executed.
16. Why use the thread pool?
Avoid frequent thread creation and destruction to reuse thread objects. In addition, you can use the thread pool to flexibly control the number of concurrency based on the project.
17. How can I check whether a thread holds an object monitor?
I also saw a multi-Thread interview question on the Internet to know whether a Thread holds an Object monitor. The Thread class provides a holdsLock (Object obj) method, true is returned only when the monitor of the object obj is held by a thread. Note that this is a static method, which means that "a thread" refers to the current thread.
18. Differences between synchronized and ReentrantLock
Synchronized is the same keyword as if, else, for, and while. ReentrantLock is a class, which is the essential difference between the two. Since ReentrantLock is a class, it provides more flexible features than synchronized, can be inherited, can have methods, and can have a variety of class variables, the scalability of ReentrantLock over synchronized is reflected in the following points:
(1) ReentrantLock can be used to set the lock wait time to avoid deadlocks.
(2) ReentrantLock can obtain information about various locks.
(3) ReentrantLock can flexibly implement multiple notifications
In addition, the lock mechanisms of the two are actually different. The underlying ReentrantLock calls the Unsafe park method locking. the synchronized operation should be mark word in the object header, which I cannot determine.
19. What is ConcurrentHashMap's concurrency?
ConcurrentHashMap concurrency is the size of the segment. The default value is 16, which means that a maximum of 16 threads can operate ConcurrentHashMap at the same time. This is also the biggest advantage of ConcurrentHashMap for Hashtable. In any situation, can Hashtable have two threads simultaneously to obtain data in Hashtable?
20. What is ReadWriteLock?
First, it is clear that ReentrantLock is not good, but ReentrantLock is limited in some cases. If ReentrantLock is used, it may be used to prevent data inconsistency caused by Data Writing by thread A and reading data by thread B. However, if thread C reads data and thread D reads data, reading data will not change the data. There is no need to lock the data, but it is still locked, reducing the program performance.
Because of this, the read/write lock ReadWriteLock was born. ReadWriteLock is a read/write lock interface, and ReentrantReadWriteLock is a specific implementation of the ReadWriteLock interface, which achieves read/write separation. Read locks are shared, write locks are exclusive, and read locks are not mutually exclusive, read and Write, write and read, write and write are mutually exclusive, improving the read/write performance.
21. What is FutureTask?
As mentioned above, FutureTask represents an Asynchronous Operation task. In FutureTask, You can input a Callable implementation class to wait for the result of the Asynchronous Operation task to be obtained, determine whether the task has been completed, and cancel the task. Of course, because FutureTask is also an implementation class of the Runnable interface, FutureTask can also be placed in the thread pool.
22. How to Find the thread with the longest CPU usage in Linux?
This is a relatively practical issue, which I think makes sense. You can do this:
(1) obtain the project pid, jps, or ps-ef | grep java, as mentioned earlier
(2) top-H-p pid, the order cannot be changed
In this way, you can print out the percentage of CPU time occupied by each thread in the current project. Note that the LWP is printed here, that is, the thread Number of the native thread of the operating system. I have not deployed a Java project in the Linux environment in my notebook, so there is no way to demonstrate it, if you are using a Linux environment to deploy a project, try it.
Using "top-H-p pid" + "jps pid", you can easily find the thread stack of a thread that occupies a high CPU, so as to locate the cause of high CPU usage, this is generally because of an endless loop caused by improper code operations.
Finally, the LWP produced by "top-H-p pid" is in decimal format, and the local thread number produced by "jps pid" is in hexadecimal format, you can locate the current thread stack that occupies the CPU.
23. Write a program programmed in Java that causes deadlock
The first time I saw this question, I thought it was a very good question. Many people know what A deadlock is like: thread A and thread B wait for the lock held by the other party to lead to an infinite endless loop of the program. Of course, this is only true. I don't know how to write a deadlock program. To put it bluntly, I just don't know what a deadlock is, and I just need to understand a theory, in practice, the deadlock problem is basically unknown.
It is not difficult to really understand what a deadlock is. There are several steps:
(1) Two threads hold two Object objects: lock1 and lock2. These two locks act as the locks for Synchronous Code blocks;
(2) synchronize the code block in the run () method of Thread 1 first to obtain the object lock of lock1, Thread. sleep (xxx), the time does not need to be too much, 50 ms is almost the same, and then get the lock2 object lock. To prevent thread 1 from being started, the lock1 and lock2 Object locks are obtained consecutively.
(3) run of thread 2 (Synchronous Code block in the method first obtains the object lock of lock2 and then obtains the object lock of lock1. Of course, the object lock of lock1 has been held by thread 1, thread 2 must wait for thread 1 to release the lock1 object lock.
In this way, thread 1 goes to bed, and thread 2 has obtained the lock2 object lock. At this time, thread 1 tries to obtain the lock2 object lock and is blocked, in this case, a deadlock occurs. The code will not be written, and it takes a lot of space.
24. How to wake up a blocked thread
If the thread is blocked because the wait (), sleep (), or join () method is called, the thread can be interrupted and the thread can be awakened by throwing InterruptedException; if the thread encounters IO blocking, there is nothing to do with it. Because I/O is implemented by the operating system, Java code cannot directly access the operating system.
25. How can immutable objects help multithreading?
One of the problems mentioned above, immutable objects ensure the visibility of the object's memory, and no additional synchronization means is required for reading immutable objects, improving the code execution efficiency.
26. What is multi-thread context switching?
Multi-thread context switching refers to the process in which the CPU control is switched from a running thread to another thread ready and waiting for obtaining the CPU execution right.
27. What will happen if the thread pool queue is full when you submit a task?
If you use the queue blockingqueue, that is, the unbounded queue, it doesn't matter. Continue to add the task to the blocking queue for execution, because the queue blockingqueue can be considered as an infinite queue, tasks can be stored infinitely. If you use a bounded queue, for example, ArrayBlockingQueue, the tasks are first added to ArrayBlockingQueue, And the ArrayBlockingQueue is full, the deny policy RejectedExecutionHandler is used to process tasks that are full. The default value is AbortPolicy.
28. What is the thread scheduling algorithm used in Java?
Preemptible. After a thread runs out of CPU, the operating system will calculate a total priority based on data such as thread priority and thread hunger and allocate the next time slice to a thread for execution.
29. What is the role of Thread. sleep (0 )?
This problem is related to the above problem, and I am connected together. Because Java uses a preemptible thread scheduling algorithm, a thread may often obtain CPU control. In order to allow some threads with lower priority to obtain CPU control, you can use Thread. sleep (0) manually triggers a time slice allocation operation by the operating system, which is also an operation to balance CPU control.
30. What is spin?
Many synchronized codes are just some simple code, and the execution time is very fast. It is not worthwhile to lock the waiting threads at this time, because thread blocking involves switching between user and kernel states. Since the code in synchronized is executed very quickly, let the thread waiting for the lock not be blocked, but do a busy loop at the boundary of synchronized, which is the spin. If the lock is not obtained after multiple busy loops, blocking may be a better strategy.
31. What is the Java memory model?
The Java Memory Model defines a specification for multi-threaded access to Java memory. The Java memory model should not be completely explained here. I will briefly summarize some of the content of the Java Memory Model:
(1) The Java memory model divides the memory into primary memory and working memory. The state of the class, that is, the shared variables between classes, is stored in the main memory. Every time the Java thread uses these variables in the main memory, it will read the variables in the main memory, make these replicas exist in your working memory and use these variables when running your own thread code. The operations are all the replicas in your working memory. After the thread code is executed, the latest value is updated to the main memory.
(2) several atomic operations are defined to operate the variables in the main memory and working memory.
(3) defines the rules for using volatile variables.
(4) happens-before, that is, the principle of first occurrence, defines some rules that action A must first occur in action B, for example, the code before the control flow in the same thread must first take place in the code behind the control flow, and an action to release the lock unlock must first take place in the action of locking the same lock., as long as these rules are met, no additional synchronization measures are required. If a code segment does not comply with all the happens-before rules, the code segment must be thread-safe.
32. What is CAS?
CAS, all called Compare and Set, that is, comparison-setting. Assume that there are three operands: memory value V, old Expected Value A, and the value B to be modified. if and only when the expected value A is the same as the memory value V, to change the memory value to B and return true. Otherwise, no action is performed and false is returned. Of course, CAS must use volatile variables to ensure that the variable obtained each time is the latest value in the main memory. Otherwise, the old Expected Value A is for A thread, it is always A value that will not change. As long as a cas operation fails, it will never succeed.
33. What are optimistic locks and pessimistic locks?
(1) optimistic lock: Like its name, it is optimistic about the thread security issues caused by concurrent operations. Optimistic locks believe that competition will not always happen, therefore, it does not need to hold the lock. Compare-set the two actions as an atomic operation to try to modify the variables in the memory. If the two actions fail, a conflict occurs, then there should be a corresponding retry logic.
(2) pessimistic lock: Like its name, we are pessimistic about the thread security issues caused by concurrent operations. pessimistic locks hold that competition will always happen, therefore, each time a resource is operated, it will hold an exclusive lock, just like synchronized. No matter November 21, the resource will be operated upon the lock.
34. What is AQS?
To put it simply, AQS is called AbstractQueuedSychronizer, which translates to abstract queue synchronizers.
If java. util. concurrent is based on CAS, AQS is the core of the entire Java concurrent package, and ReentrantLock, CountDownLatch, and Semaphore are used. In fact, AQS connects all the entries in the form of a two-way queue. For example, ReentrantLock, all the waiting threads are placed in an Entry and connected to a two-way queue. The previous thread uses ReentrantLock, the first Entry in the two-way queue is actually running.
AQS defines all operations on the two-way queue, and only opens the tryLock and tryRelease methods for developers. developers can rewrite the tryLock and tryRelease methods based on their own implementations, to achieve their own concurrent functions.
35. single-instance mode thread security
The first thing we need to talk about is the thread security of the singleton mode, which means that a class instance will only be created once in a multi-threaded environment. The Singleton mode has many writing methods. I will summarize them as follows:
(1) Writing of the hungry Chinese Singleton mode: thread security
(2) lazy Singleton mode: Non-thread security
(3) Statement of double check lock Singleton mode: thread security
36. What is the role of Semaphore?
Semaphore is a Semaphore. It is used to limit the number of concurrent code blocks. Semaphore has a constructor that can input an int-type integer n, indicating that a code segment can be accessed by up to n threads. If it exceeds n, please wait, after a thread finishes executing this code block, the next thread enters. It can be seen that if the int-type integer n = 1 passed in the Semaphore constructor is equivalent to a synchronized.
37. In the size () method of Hashtable, there is only one statement "return count". Why do we need to perform synchronization?
This is a problem I encountered before. I wonder if you have ever thought about it. If multiple statements in a method are operating on the same class variable, no lock in a multi-threaded environment will inevitably cause thread security problems, but the size () method has only one statement. Why should I lock it?
There are two main reasons for understanding this question during my work and study:
(1) At the same time, only one thread can execute Synchronization Methods of fixed classes. However, for non-synchronous methods of classes, multiple threads can simultaneously access them. So there is A problem. Maybe thread A is executing the put Method of Hashtable to add data, and thread B can normally call the size () method to read the number of current elements in Hashtable, the read value may not be the latest. Maybe thread A has added the data, but no size ++ is added, so thread B has read the size, the size read by thread B must be inaccurate. After synchronizing the size () method, it means that thread B can call the size () method only after thread A calls the put method. This ensures thread security.
(2) It is critical that the CPU executes code instead of Java code. Java code is eventually translated into assembly code for execution, and assembly code is the code that can truly interact with the hardware circuit. Even if you see only one line of Java code, and even the byte code generated after the Java code is compiled, this does not mean that there is only one operation for the underlying statement. If a "return count" clause is translated into three Assembly statements for execution, the thread switches after the first statement is executed.
38. The Thread class constructor and the thread that calls the static Block
This is a very tricky and tricky problem. Remember: the construction method and static block of the thread class are called by the thread where the new Thread class is located, and the code in the run method is called by the thread itself.
If the above statement is confusing to you, let me give you an example. If Thread1 is new in Thread2 and Thread2 is new in main function, then:
(1) the construction method and static block of Thread2 are called by the main thread, and the run () method of Thread2 is called by Thread2.
(2) The construction method and static block of Thread1 are called by Thread2, And the run () method of Thread1 is called by Thread1.
39. Which of the following is a better choice for the synchronization method and synchronization block?
Synchronous block, which means that the code outside the synchronous block is executed asynchronously, which is more efficient than synchronizing the entire method. Please know one principle: the smaller the synchronization range, the better.
With this article, I also mentioned that, although the smaller the scope of synchronization, the better, there is still an optimization method called lock Roughening in the Java Virtual Machine, this method increases the synchronization range. This is useful. For example, StringBuffer is a thread-safe class. Naturally, the most commonly used append () method is a synchronous method. When we write code, it will append strings repeatedly, this means that repeated locks> unlocking are required, which is detrimental to the performance, because it means that the Java Virtual Machine must repeatedly switch between the kernel state and the user State on this thread, therefore, the Java Virtual Machine will perform a coarse Lock operation on the code called by the append method multiple times, and extend the multiple append operations to the beginning and end of the append method to become a large synchronization block, this reduces the number of locks> unlocking times, and effectively improves the efficiency of code execution.
40. How do businesses with high concurrency and short task execution time use the thread pool? How do I use a thread pool for businesses with low concurrency and long task execution time? How do I use a thread pool for businesses with high concurrency and long service execution time?
This is a problem I have seen on the concurrent programming Web site. Put this problem at the end. I hope everyone can see and think about it, because this problem is very good, very practical, and very professional. My personal opinion on this issue is:
(1) For businesses with high concurrency and short task execution time, the number of threads in the thread pool can be set to the number of CPU cores + 1, reducing thread context switching
(2) businesses with low concurrency and long task execution time must be separated and viewed separately:
A) if the business time is concentrated on I/O operations, that is, I/O-intensive tasks, Because I/O operations do not occupy the CPU, do not let all the CPUs go idle, the number of threads in the thread pool can be increased to allow the CPU to process more services.
B) if the business is concentrated on computing operations for a long time, that is, computing-intensive tasks, there is no way to do this, just like (1, the number of threads in the thread pool is set less to reduce thread context switching.
(3) High concurrency and long service execution time. The key to solving such tasks lies not in the thread pool but in the overall architecture design, it is the first step to check whether some data in these services can be cached, and the second step is to add servers. For the thread pool settings, see (2 ). Finally, you may need to analyze the long service execution time to see if you can use middleware to split and decouple tasks.
Notes for learning Java !!!
If you have any questions or want to obtain learning resources during the learning process, join the Java learning exchange group with the group number: 618528494. Let's learn Java together!