preface

In my opinion, the more content and miscellaneous knowledge you learn, the more you need to make a profound summary, so that you can remember deeply and make the knowledge your own. This article mainly summarizes the problems of multithreading, so it lists 40 multithreading problems. These multi-threaded questions, some from the major websites, some from their own thinking. There may be some problem online, there may be some questions the corresponding answers and, also may be a little fellow netizens also are seen, but the focus of this writing is that all problems will be according to own understanding to answer again, don’t go to the online answer, so there may be some problems about wrong, can correct hope you feel free to comment.




Summary of 40 questions

1. What is the use of multithreading?

A question that may seem ridiculous to many people: why do I care if I can use multithreading? In my opinion, this answer is even more bullshit. The so-called “know what it is”, “will use” is only “know what it is”, “why to use” is “know what it is”, only to achieve “know what it is” degree can be said to be a knowledge point to use freely. OK, here’s what I think about it: (1) Play the advantages of multi-core CPU with the progress of the industry, now the notebook, desktop and even commercial application servers are at least dual-core, 4-core, 8-core and even 16-core are not uncommon, if it is a single-threaded program, then in dual-core CPU waste 50%, on the 4-core CPU waste 75%. The so-called “multithreading” on a single-core CPU is fake multithreading. The processor only processes one piece of logic at a time, but the threads switch between them so fast that it looks like multiple threads are running “simultaneously.” Multi-threading on the multi-core CPU is the real multi-threading, it can make your multi-section of logic work at the same time, multi-threading, can really play the advantages of the multi-core CPU, to make full use of the PURPOSE of the CPU. (2) prevent blocking from the point of view of program efficiency, single-core CPU not only will not play the advantages of multi-threading, but will cause the thread context switch because of running multi-threading on single-core CPU, and reduce the overall efficiency of the program. But with a single-core CPU we still have to apply multithreading just to prevent blocking. Imagine if a single-core CPU uses a single thread, and if that thread blocks, say, reading data remotely, and the peer doesn’t return and doesn’t set a timeout, your entire program will stop running before the data comes back. Multithreading prevents this problem. Multiple threads are running at the same time, and even if the code in one thread is blocked in reading data, it does not affect the execution of other tasks. (3) Ease of modeling this is another less obvious advantage. Let’s say you have A big task A, single-threaded programming, and it’s A lot to think about, and it’s A lot of trouble to model the entire program. However, if the big task A is broken down into several small tasks, task B, task C and task D, respectively build the program model, and run these tasks separately through multi-threading, it will be much simpler.

2. How threads are created

A common problem, generally is two kinds: (1) (2) inherited the Thread class implement the Runnable interface As for which good, needless to say, it must be the latter, because of the way implementing an interface method is more flexible than a derived class, also can reduce the coupling between the program, programming to an interface are also at the heart of the design patterns six principles.

3. The difference between the start() and run() methods

The multithreaded nature is only apparent when the start() method is called, and the code in the run() method is executed alternately in different threads. If only the run() method is called, the code is executed synchronously, and one thread must wait for all the code in its run() method to complete before another thread can execute its run() method.

4. Difference between Runnable interface and Callable interface

A bit of a deep question, but also see a Java programmer to learn the breadth of knowledge. The return value of the run() method in the Runnable interface is void, and all it does is execute the code in the run() method; The Call () method in the Callable interface, which returns a value, is a generic type that can be used in conjunction with Future and FutureTask to retrieve the result of asynchronous execution. And this is actually a very useful feature, because one of the big reasons that multithreading is more difficult and more complex than single threading is because multithreading is so unpredictable. Does a thread execute? How long did a thread execute? Is the expected data already assigned when a thread executes? We don’t know. All we can do is wait for the multithreaded task to finish. Callable+Future/FutureTask can retrieve the results of multiple threads. It can cancel the task if it waits too long to retrieve the required data, which is really useful.

5. Difference between CyclicBarrier and CountDownLatch

Two similar looking classes, both under java.util.concurrent, can be used to indicate that code is running at a point. The difference is that: (1) After a thread of CyclicBarrier runs to a certain point, the thread will stop running, and all threads will not restart until all threads have reached this point; CountDownLatch, on the other hand, gives a value of -1 after a thread has reached a certain point, and the thread continues to run (2) CyclicBarrier can only evoke one task. CountDownLatch can evoke multiple tasks (3) CyclicBarrier is reusable. CountDownLatch is not reusable. If the CountDownLatch is 0, the CountDownLatch is no longer available

The role of the Volatile keyword

A very important question is that every Java programmer who learns and applies multithreading must master. A prerequisite for understanding the use of volatile is an understanding of the Java memory model, which is not covered here. As you can see from Point 31, volatile serves two main purposes: (1) Multithreading is mainly based on the visibility and atomicity of the two features, using volatile variables to ensure that they are visible across multiple threads, that is, every time a volatile variable is read, it must be the latest data. (2) The low-level implementation of the code is not as simple as we see in high-level Java programs. Its execution is Java code — > bytecode — >C/C++ code executes according to bytecode — >C/C++ code is compiled into assembly language — > interacts with hardware circuits. In reality, the JVM may reorder instructions for better performance, and some unexpected problems may occur in multithreading. Ban on semantic reordering, have to use volatile and are, of course, this also to a certain extent reduce the code execution efficiency From the point of the practice, is an important role of volatile and CAS, guarantees the atomicity and detail can see Java. Util. Concurrent. The atomic classes under the package, For example, AtomicInteger.

7. What is thread safety

Again, a theoretical question, and there are many different answers, but I’ll give you the one that I think explains best: if your code always gets the same results when it executes in multiple threads as it does when it executes in a single thread, then your code is thread-safe. There are several levels of thread safety: (1) Immutable classes such as String, Integer, and Long are final and cannot be changed by any thread unless a new one is created. So these immutable objects can be used directly in a multithreaded environment without any synchronization. (2) Absolute thread-safety No matter what the runtime environment is, the caller does not need any additional synchronization. There’s a lot of extra cost to doing this, and most of the classes in Java that label themselves as thread-safe are actually not thread-safe, but there are classes in Java that are thread-safe, For example, CopyOnWriteArrayList, CopyOnWriteArraySet (3) is thread-safe, thread-safe, thread-safe, thread-safe, thread-safe, thread-safe, thread-safe, thread-safe, thread-safe, thread-safe, thread-safe, thread-safe, thread-safe, thread-safe, thread-safe, thread-safe, thread-safe, thread-safe, thread-safe, thread-safe, thread-safe, thread-safe, thread-safe, thread-safe, thread-safe. If there is a thread in traverse a Vector, there is a thread in the add this Vector at the same time, 99% of the cases will appear ConcurrentModificationException, namely fail – fast mechanism. ArrayList, LinkedList, HashMap, etc are threadsafe classes

How to obtain thread dump file in Java

Thread dump is the best way to solve problems such as dead loops, deadlocks, blocking, and slow page opening. A thread stack can be retrieved in two steps: (1) access to the thread of pid, can use the JPS command, in Linux environment can also use ps – ef | grep Java (2) the print thread stack, can use jstack pid command can also be used in a Linux environment kill 3 pid plus a bit, The Thread class provides a getStackTrace() method that can also be used to get the Thread stack. This is an instance method, so this method is tied to a specific thread instance, and each fetch gets the stack that a particular thread is currently running,

9. What happens to a thread with a runtime exception

If the exception is not caught, the thread stops executing. Another important point is that if this thread holds a monitor for an object, the object monitor is immediately released

How do I share data between two threads

This is done by sharing objects between threads, and then evoking and waiting with wait/notify/notifyAll, await/signal/signalAll. For example, BlockingQueue is designed to share data between threads

What’s the difference between sleep and wait

Sleep and wait can both be used to give up the CPU for a certain amount of time. The difference is that if a thread holds the monitor for an object, sleep does not give up the monitor for that object, while wait does

12. What is the role of the producer-consumer model

It’s a theoretical question, but an important one: (1) through balancing the producer’s production capacity and consumer spending to improve the operation efficiency of the whole system, this is the most important function of producer-consumer model (2) decoupling, this is a function of producer-consumer model attached, decoupling means the connection between the producers and consumers, contact less is also alone and do not need to receive each other’s constraints

13, ThreadLocal said what’s the use of simple ThreadLocal is a kind of to the practice of trading space for time, within each Thread maintains a open to address method to implement ThreadLocal. ThreadLocalMap, isolating data, the data is not Shared, Naturally, there are no thread-safety issues

14. Why wait() and notify()/notifyAll() are called in synchronous blocks

This is mandatory by the JDK; both wait() and notify()/notifyAll() must acquire the lock on the object before being called

15. What is the difference between wait() and notify()/notifyAll() when giving up object monitors

The difference between wait() and notify()/notifyAll() is that wait() releases the object monitor immediately, while notify()/notifyAll() waits for the rest of the thread code to complete before abandoning the object monitor.

16. Why use thread pools

Avoid frequent creation and destruction of threads to achieve reuse of thread objects. In addition, using thread pools gives you the flexibility to control the number of concurrency depending on your project.

17, how to check if a thread has object monitor

I didn’t know there was a way to tell if a thread was holding an object monitor until I saw a multi-threaded interview question online: The Thread class provides a holdsLock(Object obj) method that returns true if and only if the Object obj’s monitor is held by a Thread. Note that this is static, meaning that “Thread” refers to the current Thread.

The difference between synchronized and ReentrantLock

Synchronized is a keyword like if, else, for, and while. ReentrantLock is a class. This is the essential difference between synchronized and while. Since ReentrantLock is a class, it provides more flexible features than synchronized. It can be inherited, can have methods, and can have a variety of class variables. ReentrantLock has more extensibility than synchronized in several aspects: (1) ReentrantLock can set the waiting time for acquiring locks, so as to avoid deadlocks. (2) ReentrantLock can obtain various locks information. (3) ReentrantLock can flexibly implement multi-way notification. The underlying ReentrantLock is the Unsafe park method, while synchronized is the mark Word object header. I’m not sure.

19. What is the concurrency of ConcurrentHashMap

ConcurrentHashMap concurrency is the size of the segment. The default value is 16, which means that up to 16 threads can operate on ConcurrentHashMap at the same time. This is ConcurrentHashMap’s biggest advantage over Hashtable. Can two threads fetch data from a Hashtable at the same time?

20. What is ReadWriteLock

To be clear, it’s not that ReentrantLock is bad, it’s just that ReentrantLock is sometimes limited. ReentrantLock may be used to prevent data inconsistency caused by thread A writing data and thread B reading data. However, if thread C is reading data and thread D is also reading data, the read data does not change the data. There is no need to lock the data, but the lock is still locked, which reduces the performance of the program. Because of this, the read-write lock ReadWriteLock was born. ReadWriteLock is a read/write lock interface. ReentrantReadWriteLock is an implementation of the ReadWriteLock interface. It enables read/write separation. Improves read and write performance.

21. What is FutureTask

This was actually mentioned earlier, FutureTask represents a task for asynchronous computation. FutureTask can pass in a concrete implementation class of Callable, which can wait for the result of the asynchronous operation, determine whether the task has been completed, and cancel the task. Of course, since FutureTask is also an implementation class of the Runnable interface, it can also be put into a thread pool.

How do I find which thread uses the longest CPU in Linux

This is a practical question, which I think is quite meaningful. Can do that: (1) to obtain the pid of the project, the JSP or ps – ef | grep Java, the front has talked about (2) the top – H – p pid, the order cannot be changed So you can print out the current project, each thread is the percentage of CPU time. Note that the type here is LWP, that is, the thread number of the native thread of the operating system. I have not deployed Java projects in Linux environment, so THERE is no way to show screenshots. Friends, if the company uses Linux environment to deploy projects, you can try. Using “top-H-P PID” + “JPS PID”, it is easy to find the thread stack of a thread with a high CPU usage, thus locating the cause of the high CPU usage, which is usually due to an infinite loop caused by improper code operations. Finally, “top-H-P PID” prints LWP in decimal, and “JPS PID” prints the local thread number in hexadecimal. After conversion, we can locate the current thread stack of the thread with the highest CPU usage.

Java programming to write a program that will cause a deadlock

When I first saw this topic, I thought it was a very good question. Most people know how A deadlock works: Thread A and thread B wait for each other to hold A lock, causing the program to continue in an infinite loop. Of course, it is limited to this, ask how to write a deadlock program do not know, this situation is simply do not understand what is a deadlock, understand a theory is finished, in practice encounter deadlock problem is basically not visible. (1) Two threads hold two Object objects: lock1 and lock2. These two locks act as locks for synchronized code blocks; Thread.sleep(XXX), thread.sleep (XXX), thread.sleep (XXX), thread.sleep (XXX) (3) Thread 2’s run (method in which the synchronization code block first acquires the object lock of lock2, then acquires the object lock of lock1, of course, then the object lock of lock1 has been held by thread 1 lock). Thread 2 must wait for thread 1 to release the object lock of lock1, so thread 1 sleeps, thread 2 has acquired the object lock of Lock2, thread 1 tries to acquire the object lock of Lock2, and a deadlock is formed. I’m not going to write the code, it takes up a little bit of space.

24, How to wake up a blocked thread

If a thread is blocking because it called wait(), sleep(), or join(), you can interrupt it and wake it up by throwing InterruptedException. If the thread encounters AN IO block, there is nothing to be done, because IO is implemented by the operating system, and Java code has no direct access to the operating system.

25. How does immutable objects help multithreading

As mentioned earlier, immutable objects guarantee the memory visibility of objects, and reading immutable objects does not require additional synchronization, which improves code execution efficiency.

26. What is multithreaded context switching

Context switching in multithreading is the process of switching CPU control from one thread that is already running to another thread that is ready and waiting for CPU execution.

27. What happens if the thread pool queue is full when you submit a task

If you use LinkedBlockingQueue, which is an unbounded queue, it doesn’t matter, continue to add tasks to the blocking queue for execution, because LinkedBlockingQueue can be thought of as an almost infinite queue that can hold tasks indefinitely; If you’re using a bounded queue like ArrayBlockingQueue, the task is added to the ArrayBlockingQueue first, ArrayBlockingQueue is full, The RejectedExecutionHandler policy is used to handle the full task. The default policy is AbortPolicy.

28. What is the thread scheduling algorithm used in Java

Preemptive. After a thread runs out of CPU, the operating system calculates a total priority based on thread priority, thread hunger, etc., and allocates the next time slice to a particular thread.

What does thread.sleep (0) do

This question is related to the one above, and I’m connected. Due to Java’s preemptive Thread scheduling algorithm, it may occur that a Thread often obtains CPU control. In order to enable some threads with lower priorities to obtain CPU control, thread.sleep (0) can be used to manually trigger an operation of the operating system to allocate time slices. This is also an exercise in balancing CPU control.

30. What is spin

A lot of synchronized code is just some very simple code, the execution time is very fast, in this case, the waiting thread locking may not be a worthwhile operation, because thread blocking involves user state and kernel state switch issues. Since synchronized code executes very fast, it’s a good idea not to block a thread waiting for a lock, but to do a busy loop at synchronized’s boundary, which is known as spin. It may be a better strategy to block if you do several busy cycles and find that the lock has not been acquired.

What is the Java memory model

The Java memory model defines a specification for multithreaded access to Java memory. (1) The Java memory model divides the memory into main memory and working memory. Class status, which is Shared between classes of variables, are stored in main memory, each Java thread used variables in the main memory, will read a variables in main memory, and make those within their working memory has a copy, running his own thread code, use these variables, operation is the a in the working memory. The most recent values are updated to main memory after threaded code has completed execution (2) atomic operations are defined to operate on variables in main and working memory (3) rules for the use of volatile variables are defined (4) happens-before, Defines A must first occurred in operation of B some rules, such as in front of the control flow within the same thread code must first occurred in control flow behind the code, A release lock unlock actions must be first in the back for the same lock lock lock action and so on, should accord with these rules, you don’t need to do extra synchronous measures, If a piece of code does not comply with all the happens-before rules, it must be thread-unsafe

32. What is CAS

CAS: Compare and Set. Suppose there are three operands: the memory value V, the old expected value A, and the value to be modified B. Change the memory value to B and return true if and only if the expected value A and the memory value V are the same, otherwise do nothing and return false. Of course, CAS must be volatile to ensure that the most recent value in main memory is retrieved each time. Otherwise, the old expected value, A, will remain the same for A thread and will never succeed as long as the CAS operation fails.

What is the optimistic lock and pessimistic lock

Optimistic locking (1) : just like its name, for concurrent operation thread safety problem between state, optimistic optimistic locking that competition does not always happen, so it does not need to hold locks, set the comparison – the two actions as an atomic operation to try to modify variables in memory, if failure, said conflict, then there should be a corresponding retry logic. (2) pessimistic locks: or, like its name, for concurrent operation thread safety problem between pessimistic, pessimistic locking think competition is always happen, so every time of operating resources, will hold an exclusive lock, as synchronized, willy-nilly, directly on the lock operation resources.

34, What is AQS

Simple said AQS, called the AQS AbstractQueuedSychronizer, translation should be abstract queue synchronizer. If CAS is the foundation of java.util.Concurrent, then AQS is the core of Java and packet issuance, used by ReentrantLock, CountDownLatch, Semaphore, etc. AQS actually connect all entries in the form of bidirectional queue, for example, ReentrantLock. All waiting threads are placed in an Entry and connected into a bidirectional queue. If the previous thread uses ReentrantLock, the first Entry of the bidirectional queue actually starts to run. AQS defines all operations on two-way queues, and only the tryLock and tryRelease methods are available to developers, who can override the tryLock and tryRelease methods to implement their own concurrency.

Singleton thread safety

The threadbare issue is that singleton thread-safety means that instances of a class can only be created once in a multithreaded environment. There are many ways to write singletons, so I summarize: (1) The hunk singletons are thread-safe, (2) the lazy singletons are thread-safe, and (3) the double-lock singletons are thread-safe

36. What does Semaphore do

A Semaphore is a Semaphore that limits the number of concurrent requests for a block of code. Semaphore has a constructor that passes in an integer of type n to indicate that a piece of code can be accessed by at most n threads. If more than n is passed, wait until one thread finishes executing the block before the next thread enters. If the Semaphore constructor passes an int n=1, it becomes synchronized.

37, Hashtable size() has only one statement “return count”.

This is a puzzle I had before, and I don’t know if you’ve thought about it. If there are multiple statements in a method that operate on the same class variable, leaving the lock unlocked in a multithreaded environment will cause thread-safety problems. There are two main reasons for this problem: (1) Only one thread can execute the synchronous method of a fixed class at the same time, but for the asynchronous method of a class, multiple threads can access it at the same time. Thread B could call the size() method to read the current number of elements in the Hashtable. That might not be the latest value. Thread A might have added data, but it didn’t add size++, Thread B has already read size, so it must be inaccurate for thread B to read size. The size() method can only be called after thread A has finished calling the put method. This ensures thread-safety. (2) The CPU executes code, not Java code. Java code is ultimately translated into assembly code for execution, and assembly code is the code that can actually interact with hardware circuits. Even if you see only one line of Java code, and even if you see only one line of bytecode generated after Java code is compiled, that doesn’t mean there is only one operation for this statement to the bottom. If a “return count” is translated into three assembly sentences, it is possible to execute the first sentence before the thread switches.

38, Thread class constructor, static block is called by which thread

This is a very tricky and tricky question. Remember: the thread constructor, the static block, is called by the thread in which the new thread belongs, whereas the code in the run method is called by the thread itself. For example, if Thread1 is new in Thread2 and Thread2 is new in main, then: (1) The run() method of Thread1 is called by Thread2, and the run() method of Thread1 is called by Thread1

Synchronization method and synchronization block, which is the better choice

Synchronized blocks, which means that code outside the synchronized block is executed asynchronously, which is more efficient than synchronizing the entire method. As a rule of thumb, the less scope of synchronization the better. With this in mind, I should add that while less scope is better, there is an optimization method in the Java virtual machine called lock coarsing, which is to make the scope larger. This is useful, for example, StringBuffer, which is a thread-safe class. Naturally, the most common append() method is a synchronous method, and when we write code we repeatedly append the string, which means we repeatedly lock -> unlock, which is bad for performance, Because this means that the Java virtual machine is repeatedly switching between kernel and user mode on this thread, the Java virtual machine coarses the code for multiple Append calls into a lock, extending the multiple Append operations to the top and bottom of the Append method into a large synchronized block. This reduces the number of locks – > unlocks, effectively increasing the efficiency of code execution.

40. How can thread pools be used for high concurrency and short task execution times? How can thread pools be used for businesses with low concurrency and long task execution times? How can a business with high concurrency and long business execution time use thread pools?

This is a question I came across on the Concurrent programming web site, and I put it last so that everyone can see it and think about it, because it’s a very good, very practical, very professional question. My personal opinion on this issue is as follows: (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 to reduce the switching of thread context. (2) For businesses with low concurrency and long task execution time, we should distinguish them: A) if the business is a long time focused on IO operations, namely IO intensive tasks, because IO operations are not CPU, so don’t let all the CPU idle, and can increase the number of threads in the pool, and let the CPU more business b) if the business time is long focused on computing operation, which is computationally intensive tasks, This is no way out, and the same as (1), the number of threads in thread pool set too less, reduce the thread context switch (3) high concurrency and business execution time is long, the key to solve this type of task is not in the thread pool and in the design of the overall architecture, see if can do these business inside some of the data cache is the first step, add server is the second, For thread pool Settings, refer to (2). Finally, problems with long business execution times may also need to be analyzed to see if tasks can be split and decoupled using middleware.