Deadlocks, live locks, and starvation are problems that block the execution of multiple threads if they are active or not. If a thread has these three conditions, it is no longer active and can no longer execute normally.
1. What are live locks, starvation, no locks, deadlocks?
This article is shared with friends who need to brush the questions in the interview, I have specially arranged it. The technology inside is not clear by a few words. The answers to many questions are actually very simple, but the thinking and logic behind them are not simple. If you want to learn Java engineering, high performance and distributed, simple. Performance tuning, Spring, MyBatis, Netty source code, data structure, JVM, multithreading and so on, due to the space is limited, the following only show a small part of the interview questions, there is a need for a complete version of the friend can click a link jump to get,Link: Stamp here free download, get code: nuggets
A deadlock
Deadlock is the worst situation in multithreading, multiple threads occupy each other’s resource lock, and each other to release the lock, if there is no external intervention, these threads have been dealing with the blocking of the suspended state, the formation of deadlock.
For example, student A grabbed student B’s pen, student B grabbed student A’s book, both of them were using each other’s things, asking the other to return them to themselves before returning them, so they kept arguing and waiting for the other to return them, but they could not get A solution.
So the teacher learns about it and asks them to give it back to each other, so that they can solve it with some outside intervention, and of course this is just an example of how they can solve it very well without the teacher, the computer is not like a human and if it finds out that this is going to happen without any outside intervention it’s going to keep clogging up.
Live lock
Live locking is a concept that very few of you have heard of or understand, and in multithreading it does exist.
A live lock is the opposite of a deadlock, in which no one can get a resource and each person occupies the resource of the other.
A live lock occurs when multiple threads give and take, each actively releasing a resource to another thread, so that the resource jumps between threads and is not executed.
hunger
We know that there is a thread priority in multithreaded execution, and the thread with the highest priority can cut the queue and execute first, so that if the thread with the highest priority keeps grabbing the resources of the thread with the lowest priority, the thread with the lowest priority cannot execute, this is hunger.
Of course, there is also a starvation situation, where one thread is holding on to a resource and the other threads are not executing. Unlike deadlocks, starvation can be executed at a later time, such as when the hogging thread terminates and releases the resource.
unlocked
No lock, that is, no resource is locked. That is, all threads can access and modify the same resource, but only one thread can modify the resource successfully.
The typical feature of lockless is that each modification operation is performed within a loop, and the thread will continuously attempt to modify the shared resource. If there are no conflicts, the modification succeeds and the thread will exit. Otherwise, the next loop attempt will continue.
Therefore, if multiple threads modify the same value, one thread will succeed, and the others will try again and again until the modification succeeds. In the previous article, I introduced the CAS principle and application of the JDK, namely, the lock-free implementation.
It can be seen that no lock is a very good design, it will not appear the thread jump problem, the improper use of lock will certainly appear system performance problems, although no lock can not completely replace the lock, but no lock is very efficient in some occasions.
The main difference between processes and threads is that they are different ways of managing operating system resources. Processes have independent address space, a crash of a process in protected mode does not affect other processes, and threads are just different execution paths within a process.
Thread has its own stack and local variables, but there is no separate address space between threads, a thread dead is equal to the whole process dead, so multi-process procedures than multithreaded procedures robust, but in the process switch, the cost of resources is larger, the efficiency is poor.
However, for concurrent operations that require simultaneous and variable sharing, only threads, not processes, can be used.
3. How can Java implement threads?
(1) Inherit Thread class to achieve multithreading
(2) Implementation of Runnable interface to achieve multithreading
(3) Implement multithreading with returns using ExecutorService, Callable, and Future
(4) Create a thread from a thread pool
4. What is the difference between 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.
5. How to terminate a thread? How do I gracefully terminate a thread?
Stop Stop is not recommended.
6. What are the states of a thread life cycle? How do they flow from one to the other?
NEW: Indicates that the thread has not been started yet.
RUNNABLE: indicates that the thread has triggered the start() call. The thread is officially started and in the running state.
BLOCKED: The thread is BLOCKED and waiting for the lock. For example, when the critical area is occupied by keywords such as synchronized and lock, the thread continues to run in RUNNABLE state once the lock is obtained.
WAITING: It indicates that the thread is in an unrestricted wait state, waiting for a special event to wake up. For example, the thread waiting by wait() waits for a notify() or notifyAll() method, and the thread waiting by join() waits for the end of the target thread to wake up. Once the thread is woken up with an event, the thread enters the RUNNABLE state and continues running.
TIMED_WAITING: indicates that the thread has entered a time-limited wait, such as sleep(3000). After 3 seconds, the thread resumes RUNNABLE state and continues running.
TERMINATED: Indicates that the thread TERMINATED after execution is complete. Note that once a thread is started using the start method, it can never return to its original NEW state, nor can it return to the RUNNABLE state after it terminates.
7. What is the difference between wait() and sleep() methods in threads?
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.
8. What are the methods of multithreading synchronization?
Synchronized keyword, Lock Lock implementation, distributed Lock and so on.
9. What does multithreading do?
- With the progress of the industry, now 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 50% of the dual-core CPU is wasted. 75% is wasted on 4-core cpus.
The so-called “multithreading” on a single-core CPU is false 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 achieve the purpose of using CPU.
- To prevent blocking
From the point of view of program efficiency, single-core CPU will not give full play to the advantages of multithreading, but will cause the thread context switch for running multithreading on single-core CPU, and reduce the overall efficiency of the program. But with a single-core CPU we still have to apply multiple threads, just to prevent blocking. Imagine if a single-core CPU uses a single thread, and if that thread blocks, say, reading data remotely, the other end doesn’t return it and doesn’t set a timeout, then your entire program will stop running before the data comes back.
Multithreading prevents this problem. Multiple threads are running at the same time. Even if the code in one thread is blocked from reading data, it does not affect the execution of other tasks.
- Facilitate modeling
This is another advantage that is not so obvious. 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. But if this big task A is broken down into several small tasks, task B, task C, task D, respectively establish the program model, and run these tasks through multithreading, it will be much simpler.
10. How do multiple threads communicate with each other?
wait/notify
How does the thread get the result?
Implement Callable interface.
12, Violatile keyword function?
A very important question is that every Java programmer who learns and applies multithreading must master. A prerequisite for understanding the role of volatile is an understanding of the Java memory model, which is not discussed here. As you can see from Point 31, volatile serves two main purposes:
- The use of the volatile keyword to modify variables ensures that they are visible across multiple threads. In other words, each read of a volatile variable must be the latest data.
- The underlying implementation of the code is not as simple as the high-level language —-Java program we see, its execution is Java code — > bytecode — > according to the bytecode implementation of the corresponding C/C++ code — >C/C++ code is compiled into assembly language — > and hardware circuit interaction, in reality, The JVM may reorder instructions for better performance, and some unexpected problems can occur with multithreading.
The use of volatile prevents semantic reordering and, of course, reduces the efficiency of code execution to some extent. In practical terms, one of the most important uses of volatile is to combine with CAS.
13. Create three threads T1, T2 and T3, how to ensure that they are executed in sequence?
Use join.
How to control only 3 threads running at the same time?
Use the Semaphore.
15. Why use thread pools?
We know that without a Thread pool, each Thread needs to create and run a new Thread(xxRunnable).start(). This is not a problem if there are fewer threads.
In a real environment, multiple threads can be opened to maximize the efficiency of the system and programs, depleting CPU and memory resources when the number of threads reaches a certain level, and also causing frequent GC collections and pauses because each thread created and destroyed consumes system resources.
Creating threads for each task is a significant performance bottleneck. Therefore, thread reuse in the thread pool greatly saves system resources, and it also destroys itself when the thread has no work to do for a period of time, rather than remaining in memory.