Below are some Java thread-related interview questions that I collected and sorted out by myself. You can use them to prepare well for the interview.
If you have any questions, please feel free to ask and let’s make progress together! 1) What is a thread? A thread is the smallest unit that the operating system can schedule operations on. It is contained in a process and is the actual operating unit in the process. Programmers can use it to program multiple processors. You can use multithreading to speed up computationally intensive tasks. For example, if a thread takes 100 milliseconds to complete a task, then using ten threads only takes 10 milliseconds to complete the task. 2) What is the difference between a thread and a process? A process is a self-contained execution environment, which can be considered as a program or an application. A thread is a task executed in a process. A thread is a subset of a process. A process can have many threads, each of which executes different tasks in parallel. Different processes use different memory spaces, while all threads share the same memory space. Don't confuse it with stack memory, each thread has a separate stack memory to store local data. 3) How to implement threads in Java? There are two ways to create a thread: one is to implement the Runnable interface and then pass it to the Thread constructor to create a Thread object; the other is to directly inherit the Thread class. 4) Use Runnable or Thread? This question is a follow-up to the previous one. We all know that we can implement threads by inheriting the Thread class or calling the Runnable interface. The question is, which method is better? When should it be used? This question is easy to answer if you know that Java does not support multiple inheritance of classes, but allows you to call multiple interfaces. So if you want to inherit other classes, of course it is better to call the Runnable interface. Click here for more details. 6) What is the difference between start() and run() methods in Thread class? The start() method is used to start a newly created thread and make the created thread state runnable. When you call the run() method, it will only be called in the original thread. No new thread is started. The start() method will start a new thread. If we call the run() method of Thread, it will behave like a normal method and run the run() method directly. In order to execute our code in a new thread, we must use the Thread.start() method. 7) What is the difference between Runnable and Callable in Java? Both Runnable and Callable represent tasks to be executed in different threads. Runnable has been available since JDK1.0, and Callable was added in JDK1.5. The main difference between them is that the call() method of Callable can return values and throw exceptions, while the run() method of Runnable does not have these functions. Callable can return a Future object containing the calculation result. 8) What is the difference between CyclicBarrier and CountDownLatch in Java? Both CyclicBarrier and CountDownLatch can be used to make a group of threads wait for other threads. Unlike CyclicBarrier, CountdownLatch cannot be reused. 9) What is the Java memory model? The Java Memory Model specifies and guides Java programs to behave deterministically across different memory architectures, CPUs, and operating systems. It is particularly important in the case of multithreading. The Java Memory Model provides guarantees that changes made by one thread are visible to other threads, with a happens-before relationship between them. This relationship defines some rules that make programmers think more clearly when programming concurrently. For example, the happens-before relationship ensures that: - The code within a thread can be executed in a sequential order, which is called the program order rule. - For the same lock, an unlock operation must occur before another lock operation that occurs later in time, also known as the monitor lock rule. - The previous write operation to volatile occurs before the next read operation to volatile, also known as the volatile variable rule. - Any operation within a thread must be performed after the start() call of this thread, also known as the thread startup rule. - All operations of a thread will be completed before the thread terminates, and the thread termination rules are followed. - The finalization of an object must be performed after the construction of the object is completed, also known as the object finalization rule. - Deliverability It is strongly recommended that you read Chapter 16 of "Java Concurrency Programming Practice" to deepen your understanding of the Java memory model. 10) What is volatile variable in Java? Volatile is a special modifier that can only be used for member variables. In the absence of synchronization classes in Java concurrent programs, multi-threaded operations on member variables are transparent to other threads. Volatile variables can ensure that the next read operation will occur after the previous write operation. The thread will read the variable directly from the memory and will not cache it. This ensures that the variable read by the thread is consistent with the memory. 11) What is thread safety? Is Vector a thread-safe class? If your code is in a process where multiple threads are running at the same time, these threads may run this code at the same time. If the results of each run are the same as the results of a single thread run, and the values of other variables are the same as expected, it is thread safe. The same instance of a thread-safe counter class will not make calculation errors when used by multiple threads. Obviously, you can divide collection classes into two groups, thread-safe and non-thread-safe. Vector uses synchronization methods to achieve thread safety, while the similar ArrayList is not thread-safe. 12) What is a race condition in Java? In most real-world multithreaded applications, two or more threads need to share access to the same data. What happens if the threads access the same object, and each thread calls a method that modifies the state of the object? You can imagine that the threads are stepping on each other's toes. Depending on the order in which the threads access the data, corrupted objects may be produced. Such situations are often called race conditions. 13) How to stop a thread in Java? Java provides a rich API but does not provide an API for stopping threads. JDK 1.0 originally had some control methods like stop(), suspend() and resume(), but due to the potential threat of deadlock, they were deprecated in subsequent JDK versions. Since then, the designers of the Java API have not provided a compatible and thread-safe method to stop a thread. The thread will automatically end when the run() or call() method is executed. If you want to manually end a thread, you can use a volatile Boolean variable to exit the loop of the run() method or cancel the task to interrupt the thread. 14) What happens if an exception occurs while a thread is running? If the exception is not caught, the thread will stop executing. Thread.UncaughtExceptionHandler is a built-in interface for handling sudden interruptions of threads caused by uncaught exceptions. When an uncaught exception will cause a thread to be interrupted, the JVM will use Thread.getUncaughtExceptionHandler() to query the thread's UncaughtExceptionHandler and pass the thread and exception as parameters to the handler's uncaughtException() method for processing. 15) How to share data between two threads? You can achieve this by sharing objects, or by using concurrent data structures like blocking queues. This tutorial "Communication between Java threads" (which involves sharing objects between two threads) implements the producer-consumer model using the wait and notify methods. 16) What is the difference between notify and notifyAll in Java? This is another tricky question, because multiple threads can wait on a single monitor lock, and the designers of the Java API provide some methods to notify them when the waiting condition changes, but these methods are not fully implemented. The notify() method cannot wake up a specific thread, so it is only useful when only one thread is waiting. The notifyAll() method wakes up all threads and allows them to compete for the lock, ensuring that at least one thread can continue to run. 17) Why are wait, notify and notifyAll methods not in thread class? One obvious reason is that the locks provided by JAVA are at the object level rather than the thread level. Each object has a lock, which is acquired by the thread. If the thread needs to wait for some lock, then it makes sense to call the wait() method in the object. If the wait() method is defined in the Thread class, it is not obvious which lock the thread is waiting for. In short, since wait, notify and notifyAll are all lock-level operations, they are defined in the Object class because locks belong to objects. 18) What is ThreadLocal variable? ThreadLocal is a special variable in Java. Each thread has a ThreadLocal, which means each thread has its own independent variable, and the race condition is completely eliminated. If each thread is provided with its own unique copy of the variable, the efficiency will be greatly improved. First, the number of expensive objects created is reduced through reuse. Second, you get thread safety without using expensive synchronization or immutability. 19) What is FutureTask? In Java concurrent programs, FutureTask represents an asynchronous operation that can be canceled. It has methods for starting and canceling operations, querying whether operations are completed, and retrieving operation results. Results can only be retrieved when the operation is completed. If the operation is not completed, the get method will be blocked. A FutureTask object can wrap objects that call Callable and Runnable. Since FutureTask also calls the Runnable interface, it can be submitted to the Executor for execution. 20) What is the difference between interrupted and isInterruptedd methods in Java? The main difference between interrupted() and isInterrupted() is that the former will clear the interrupt status while the latter will not. The interrupt mechanism of Java multithreading is implemented with internal flags. Calling Thread.interrupt() to interrupt a thread will set the interrupt flag to true. When the interrupted thread calls the static method Thread.interrupted() to check the interrupt status, the interrupt status will be cleared. The non-static method isInterrupted() is used to query the interrupt status of other threads and will not change the interrupt status flag. Simply put, any method that throws an InterruptedException will clear the interrupt status. In any case, the interrupt status of a thread may be changed by calling interrupts from other threads. 21) Why should wait and notify methods be called in synchronized blocks? When a thread needs to call the wait() method of an object, the thread must have the lock of the object, then it will release the object lock and enter the waiting state until other threads call the notify() method on the object. Similarly, when a thread needs to call the notify() method of an object, it will release the lock of the object so that other waiting threads can get the object lock. Since all these methods require the thread to hold the lock of the object, this can only be achieved through synchronization, so they can only be called in synchronized methods or synchronized blocks. If you don't do this, the code will throw an IllegalMonitorStateException. 22) Why should you check wait conditions in loops? A thread in a waiting state may receive false alarms and false wakeups. If you do not check the waiting condition in a loop, the program will exit without satisfying the end condition. Therefore, when a waiting thread wakes up, it cannot be assumed that its original waiting state is still valid. It may change during the period between the notify() method call and the waiting thread waking up. This is why it is better to use the wait() method in a loop. You can create a template in Eclipse to call wait and notify to give it a try. If you want to learn more about this issue, I recommend you read the thread and synchronization chapter in the book "Effective Java". 23) What is the difference between synchronized collections and concurrent collections in Java? Both synchronized collections and concurrent collections provide suitable thread-safe collections for multithreading and concurrency, but concurrent collections are more scalable. Before Java 1.5, programmers only had synchronized collections to use, which would cause contention when multiple threads were running concurrently, hindering the scalability of the system. Java 5 introduced concurrent collections such as ConcurrentHashMap, which not only provides thread safety but also improves scalability with modern technologies such as lock separation and internal partitioning. For more details, see the answer. 24) What is the difference between heap and stack in Java? Why is this question classified in the multithreading and concurrency interview questions? Because the stack is a memory area that is closely related to threads. Each thread has its own stack memory, which is used to store local variables, method parameters and stack calls. Variables stored in one thread are not visible to other threads. The heap is a common memory area shared by all threads. Objects are created in the heap. In order to improve efficiency, the thread will cache a variable from the heap to its own stack. If multiple threads use the variable, it may cause problems. At this time, the volatile variable can play a role, which requires the thread to read the value of the variable from the main memory. See the answer for more details. 25) What is a thread pool? Why use it? Creating threads takes expensive resources and time. If threads are created only when tasks arrive, the response time will be longer, and the number of threads that a process can create is limited. To avoid these problems, several threads are created when the program starts to respond to processing. They are called thread pools, and the threads in them are called worker threads. Starting from JDK1.5, Java API provides an Executor framework that allows you to create different thread pools. For example, a single thread pool processes one task at a time; a fixed number of thread pools or a cache thread pool (an expandable thread pool suitable for programs with many short-lived tasks). 26) How to write code to solve the producer-consumer problem? In reality, many thread problems you solve belong to the producer-consumer model, where one thread produces tasks for other threads to consume. You must know how to communicate between threads to solve this problem. A relatively low-level method is to use wait and notify to solve this problem, and a better method is to use Semaphore or BlockingQueue to implement the producer-consumer model. 27) How to avoid deadlock? Deadlock in Java multithreading Deadlock refers to a phenomenon in which two or more processes are waiting for each other due to competition for resources during execution. Without external forces, they will not be able to move forward. This is a serious problem because deadlock will cause your program to hang and be unable to complete the task. Deadlock must meet the following four conditions: - Mutual exclusion condition: A resource can only be used by one process at a time. - Request and hold condition: When a process is blocked for requesting resources, it holds on to the resources it has obtained. - Non-deprivation condition: The resources obtained by the process cannot be forcibly deprived before they are fully used. - Circular waiting condition: A circular waiting resource relationship is formed between several processes, with each process connected head to tail. The simplest way to avoid deadlock is to prevent circular waiting conditions, set flags and sort all resources in the system, and stipulate that all processes applying for resources must operate in a certain order (ascending or descending) to avoid deadlock. 28) What is the difference between livelock and deadlock in Java? This is an extension of the previous question. Livelock is similar to deadlock, but the difference is that the state of the thread or process in livelock is constantly changing. Livelock can be considered a special kind of starvation. A real-life example of livelock is two people meeting in a narrow corridor. Both try to avoid each other so that they can pass through, but because they avoid in the same direction, neither can pass through the corridor. Simply put, the main difference between livelock and deadlock is that the state of the process in the former can change but cannot continue to execute. 29) How to detect whether a thread owns a lock? There is a method in java.lang.Thread called holdsLock(), which returns true if and only if the current thread owns the lock of a specific object. 30) How do you get the thread stack in Java? There are different ways to get the thread stack of a Java process for different operating systems. When you get the thread stack, the JVM will save the status of all threads to a log file or output it to the console. In Windows, you can use the Ctrl + Break key combination to get the thread stack, and in Linux, use the kill -3 command. You can also use the jstack tool to get it, which operates on the thread id, and you can use the jps tool to find the id. 31) Which parameter in JVM is used to control the thread stack size? This is a simple question. The -Xss parameter is used to control the thread stack size. You can check the JVM configuration list to learn more about this parameter. 32) What is the difference between synchronized and ReentrantLock in Java? For a long time, Java could only use the synchronized keyword to implement mutual exclusion, which has some disadvantages. For example, you cannot extend the method or block boundary outside the lock, and you cannot cancel the attempt to acquire the lock. Java 5 provides more complex control through the Lock interface to solve these problems. The ReentrantLock class implements Lock, which has the same concurrency and memory semantics as synchronized and is also scalable. 33) There are three threads T1, T2, and T3. How to ensure that they are executed in sequence (ensure that the thread where the main() method is located is the last thread to terminate the Java program)? There are many ways to make threads execute in a specific order in multithreading. You can use the join() method of the thread class to start another thread in one thread, and the other thread will continue to execute after it completes. In order to ensure the order of the three threads, you should start the last one first (T3 calls T2, T2 calls T1), so that T1 will be completed first and T3 will be completed last. 34) What is the function of the yield method in the Thread class? The yield method can pause the currently executing thread object and allow other threads with the same priority to execute. It is a static method and only guarantees that the current thread gives up the CPU occupation but cannot guarantee that other threads will definitely occupy the CPU. The thread that executes yield() may be executed again immediately after entering the paused state. Click here to view more information about the yield method. #p# 35) What is the concurrency of ConcurrentHashMap in Java? ConcurrentHashMap divides the actual map into several parts to achieve its scalability and thread safety. This division is achieved using concurrency, which is an optional parameter of the ConcurrentHashMap class constructor, and the default value is 16, so that contention can be avoided in multi-threaded situations. 36) What is Semaphore in Java? Semaphore in Java is a new synchronization class that is a counting signal. Conceptually, a semaphore maintains a collection of permits. Each acquire() blocks if necessary until a permit is available, and then acquires the permit. Each release() adds a permit, potentially releasing a blocked acquirer. However, instead of using actual permit objects, Semaphore only counts the number of available permits and takes appropriate action. Semaphores are often used in multi-threaded code, such as database connection pools. More details can be found here. 37) If you submit a task and the thread pool queue is full, what will happen? This question is very tricky, and many programmers will think that the task will block until there is an empty space in the thread pool queue. In fact, if a task cannot be scheduled for execution, the ThreadPoolExecutor's submit() method will throw a RejectedExecutionException. 38) What is the difference between submit() and execute() methods in Java thread pool? Both methods can submit tasks to the thread pool. The return type of the execute() method is void, which is defined in the Executor interface, while the submit() method can return a Future object holding the calculation result. It is defined in the ExecutorService interface, which extends the Executor interface. Other thread pool classes like ThreadPoolExecutor and ScheduledThreadPoolExecutor have these methods. Click here for more details. 39) What is a blocking method? A blocking method means that the program will wait for the method to complete and will not do anything else. The accept() method of ServerSocket waits for the client to connect. The blocking here means that the current thread will be suspended before the call result is returned, and will not return until the result is obtained. In addition, there are asynchronous and non-blocking methods that return before the task is completed. Click here for more details. 40) What is your understanding of thread priority? Each thread has a priority. Generally speaking, a high-priority thread will have priority when running, but this depends on the implementation of thread scheduling, which is OS dependent. We can define the priority of a thread, but this does not guarantee that a high-priority thread will be executed before a low-priority thread. The thread priority is an int variable (from 1-10), 1 represents the highest priority, and 10 represents the lowest priority. 41) What is Thread Scheduler and Time Slicing? The thread scheduler is an operating system service that is responsible for allocating CPU time to threads in the Runnable state. Once we create a thread and start it, its execution depends on the implementation of the thread scheduler. Time slicing refers to the process of allocating available CPU time to available Runnable threads. CPU time can be allocated based on thread priority or the time a thread has been waiting. Thread scheduling is not controlled by the Java virtual machine, so it is better to let the application control it (that is, don't let your program depend on thread priority). 42) In multithreading, what is context-switching? Context switching is the process of storing and restoring the CPU state, which enables thread execution to resume from the point where it was interrupted. Context switching is an essential feature of multitasking operating systems and multithreaded environments. 43) How to create Immutable objects in Java? Immutable objects can be shared without synchronization, reducing the synchronization overhead for concurrent access to the object. To create an immutable class, you need to implement the following steps: initialize all members through the constructor, do not provide setter methods for variables, declare all members as private, so that direct access to these members is not allowed, and in the getter method, do not directly return the object itself, but clone the object and return a copy of the object. 44) What is ReadWriteLock in Java? Generally speaking, read-write locks are the result of lock separation technology used to improve the performance of concurrent programs. ReadWriteLock in Java is a new interface added in Java 5. A ReadWriteLock maintains a pair of associated locks, one for read-only operations and one for writing. In the absence of a writing thread, a read lock may be held by multiple reading threads at the same time. The write lock is exclusive. You can use ReentrantReadWriteLock in JDK to implement this rule. It supports up to 65535 write locks and 65535 read locks. 45) What is a busy loop in multithreading? A busy loop is a loop that programmers use to make a thread wait. Unlike traditional methods such as wait(), sleep() or yield(), which all give up CPU control, a busy loop does not give up the CPU. It just runs an empty loop. The purpose of this is to preserve the CPU cache. In a multi-core system, a waiting thread may run on another core when it wakes up, which will rebuild the cache. In order to avoid rebuilding the cache and reduce the time waiting for the rebuild, it can be used. 46) What is the difference between volatile variables and atomic variables? This is an interesting question. First, volatile variables and atomic variables look very similar, but they have different functions. Volatile variables can ensure precedence, that is, write operations will occur before subsequent read operations, but they cannot guarantee atomicity. For example, if the count variable is modified with volatile, the count++ operation is not atomic. The atomic methods provided by the AtomicInteger class can make such operations atomic. For example, the getAndIncrement() method will atomically perform increment operations to add one to the current value. Similar operations can also be performed on other data types and reference variables. 47) What happens if a thread inside a synchronized block throws an exception? This question has stumped many Java programmers. If you can answer it by thinking of whether the lock is released, you have a chance to get it right. Whether your synchronized block exits normally or abnormally, the thread inside will release the lock. Therefore, compared with the lock interface, we prefer synchronized blocks because it does not require energy to release the lock. This function can be achieved by releasing the lock in the finally block. 48) What is double-checked locking in the singleton pattern? This question is often asked in Java interviews, but the interviewer's satisfaction with the answer to this question is only 50%. Half of the interviewees cannot write double-checked locks and half of them cannot explain its hidden dangers and how Java 1.5 fixes it. It is actually an old method for creating thread-safe singletons. When the singleton instance is first created, it tries to use a single lock for performance optimization, but it fails in JDK 1.4 because it is too complicated. 49) How to create a thread-safe Singleton in Java? This is a follow-up to the question above. If you don't like double-checked locking and the interviewer asks about alternative ways to create a Singleton class, you can use the JVM's class loading and static variable initialization features to create a Singleton instance, or you can use an enumeration type to create a Singleton. 50) Write down 3 best practices you follow for multithreading The following three best practices should be followed by most Java programmers: - Give your threads meaningful names. This makes it easier to find bugs or track them. Names like OrderProcessor, QuoteProcessor or TradeProcessor are much better than Thread-1, Thread-2 and Thread-3. Give threads a name related to the task it is supposed to complete. All major frameworks and even JDK follow this best practice. - Avoid locking and reduce the scope of synchronization Locks are expensive and context switching is more time-consuming and space-consuming. Try to use synchronization and locks to the maximum extent to reduce the critical area. Therefore, I prefer synchronized blocks to synchronized methods, which give me absolute control over locks. - Use more synchronization classes and less wait and notify First, synchronization classes such as CountDownLatch, Semaphore, CyclicBarrier and Exchanger simplify coding operations, while it is difficult to control complex control flows using wait and notify. Second, these classes are written and maintained by leading companies and will continue to be optimized and improved in subsequent JDKs. Using these higher-level synchronization tools, your program can be optimized without any effort. - Use concurrent collections more often and synchronized collections less often This is another best practice that is easy to follow and has huge benefits. Concurrent collections are more scalable than synchronized collections, so it is better to use concurrent collections in concurrent programming. If you need to use map next time, you should first think of using ConcurrentHashMap. 51) How to force a thread to start? This question is like how to force Java garbage collection. There is no way to do it. Although you can use System.gc() to perform garbage collection, it is not guaranteed to succeed. There is no way to force a thread to start in Java. It is controlled by the thread scheduler and Java does not publish the relevant API. 52) What is the fork join framework in Java? The fork join framework is an efficient tool that appeared in JDK7. Java developers can use it to take full advantage of the multi-processors on modern servers. It is designed specifically for those that can be recursively divided into many sub-modules, with the aim of using all available processing power to improve program performance. A huge advantage of the fork join framework is that it uses a work stealing algorithm, where a worker thread that can complete more tasks can steal tasks from other threads to execute. 53) What is the difference between calling wait() and sleep() methods in Java multithreading? In Java programs, wait and sleep both cause some form of pause, and they can meet different needs. The wait() method is used for inter-thread communication. If the waiting condition is true and other threads are awakened, it will release the lock, while the sleep() method only releases CPU resources or stops the current thread from executing for a period of time, but does not release the lock. It should be noted that sleep() does not terminate the thread. Once the thread is awakened from sleep, the thread state will be changed to Runnable, and it will be executed according to the thread scheduling. 54) What is Thread Group? Why is it not recommended to use it? ThreadGroup is a class whose purpose is to provide information about a thread group. The ThreadGroup API is relatively weak, and it does not provide more functionality than Thread. It has two main functions: one is to get a list of active threads in the thread group; the other is to set an uncaught exception handler for the thread. However, in Java 1.5, the Thread class also added the setUncaughtExceptionHandler(UncaughtExceptionHandler eh) method, so ThreadGroup is outdated and is not recommended to continue using. 55) What is a Java Thread Dump and how to get it? A thread dump is a list of active threads in a JVM, which is very useful for analyzing system bottlenecks and deadlocks. There are many ways to obtain thread dumps - using Profiler, Kill -3 command, jstack tool, etc. We prefer jstack tool because it is easy to use and comes with JDK. Since it is a terminal-based tool, we can write some scripts to generate thread dumps regularly for analysis. 56) What is Java Timer class? How to create a task with a specific time interval? java.util.Timer is a utility class that can be used to schedule a thread to execute at a specific time in the future. The Timer class can be used to schedule one-time tasks or periodic tasks. java.util.TimerTask is an abstract class that implements the Runnable interface. We need to inherit this class to create our own scheduled tasks and use Timer to schedule their execution. 57) What are atomic operations? What are the atomic classes in Java Concurrency API? An atomic operation is an operation task unit that is not affected by other operations. Atomic operations are necessary to avoid data inconsistency in a multi-threaded environment. int++ is not an atomic operation, so when one thread reads its value and adds 1, another thread may read the previous value, which will cause an error. This changed with the addition of atomic variable classes in the java.util.concurrent.atomic package. All atomic variable classes expose compare-and-set primitives (similar to compare-and-swap) that are implemented using the fastest native structures available on the platform (compare-and-swap, load-link/store-conditional, and spin locks in the worst case). Nine flavors of atomic variables are provided in the java.util.concurrent.atomic package ( AtomicInteger; AtomicLong; AtomicReference; AtomicBoolean; atomic integer; long; reference; and array forms of atomic tagreference and stampreference classes, which atomically update a pair of values). 58) What is the Lock interface in Java Concurrency API? What are its advantages over synchronization? The Lock interface provides more extensible locking operations than synchronized methods and synchronized blocks. They allow more flexible structures that can have completely different properties and can support condition objects of multiple related classes. Its advantages are: - Can make locks fairer - Allows threads to respond to interrupts while waiting for a lock - Allows the thread to try to acquire the lock and return immediately or wait for a while if the lock cannot be acquired - Locks can be acquired and released in different scopes and in different orders 59) What is the Executor framework? The Executor framework along with the java.util.concurrent.Executor interface was introduced in Java 5. The Executor framework is a framework for invoking, scheduling, executing, and controlling asynchronous tasks according to a set of execution strategies. Restricted thread creation can cause application memory overflow. Therefore, creating a thread pool is a better solution because it can limit the number of threads and recycle and reuse them. Using the Executor framework, it is very convenient to create a thread pool. 60) What is the Executors class? Executors provides some utility methods for the Executor, ExecutorService, ScheduledExecutorService, ThreadFactory, and Callable classes. Executors can be used to easily create thread pools. 61) What is a blocking queue? How can we use a blocking queue to implement the producer-consumer model? The characteristics of java.util.concurrent.BlockingQueue are: when the queue is empty, the operation of getting or deleting elements from the queue will be blocked, or when the queue is full, the operation of adding elements to the queue will be blocked. Blocking queues do not accept null values, and when you try to add a null value to the queue, it will throw a NullPointerException. Blocking queue implementations are all thread-safe, and all query methods are atomic and use internal locks or other forms of concurrency control. The BlockingQueue interface is part of the Java collections framework, and it is mainly used to implement producer-consumer problems. 62) What are Callable and Future? Java 5 introduced the java.util.concurrent.Callable interface in the concurrency package, which is very similar to the Runnable interface, but it can return an object or throw an exception. The Callable interface uses generics to define its return type. The Executors class provides some useful methods to execute tasks within a Callable in a thread pool. Since the Callable task is parallel, we must wait for the result it returns. The java.util.concurrent.Future object solves this problem for us. After the thread pool submits the Callable task, a Future object returns. Using it, we can know the status of the Callable task and get the execution result returned by the Callable. Future provides the get() method so that we can wait for the Callable to end and get its execution result. 63) What is FutureTask? The FutureTask wrapper is a very convenient mechanism that converts Callable into Future and Runnable, which implements the interface between both. The FutureTask class is an implementation of Future and implements Runnable, so it can be executed through Excutor (thread pool). It can also be passed to the Thread object for execution. If you need to perform time-consuming operations in the main thread but don't want to block the main thread, you can hand over these jobs to the Future object to complete in the background. When the main thread needs it in the future, you can obtain the calculation results or execution status of the background job through the Future object. 64) What is the implementation of concurrent containers? Java collection classes all fail quickly, which means that when the set is changed and a thread uses the iterator to traverse the set, the iterator's next() method will throw a ConcurrentModificationException exception. Concurrent container: Concurrent containers are designed for concurrent access to multiple threads. The concurrent package is introduced in jdk5.0, which provides many concurrent containers, such as ConcurrentHashMap, CopyOnWriteArrayList, etc. Concurrent containers use a completely different locking strategy from synchronous containers to provide higher concurrency and scalability. For example, a finer granular locking mechanism is adopted in ConcurrentHashMap, which can be called segmented locking. Under this locking mechanism, any number of read threads are allowed to access maps concurrently, and the threads that perform read operations and the threads that write operations can also access maps concurrently, while a certain number of write threads are allowed to modify maps concurrently, so it can achieve higher throughput in a concurrent environment. 65) What is the difference between user threads and daemon threads? When we create a thread in a Java program, it is called a user thread. A daemon thread is a thread that executes in the background and does not block the JVM from terminating. When no user thread is running, the JVM closes the program and exits. The child thread created by a daemon thread is still a daemon thread. 66) What are the different thread life cycles? When we create a new thread in a Java program, its state is New. When we call the start() method of the thread, the state is changed to Runnable. The thread scheduler allocates CPU time to the threads in the Runnable thread pool and changes their state to Running. Other thread states include Waiting, Blocked and Dead. 67) How do threads communicate? When inter-thread resources can be shared, inter-thread communication is an important means to coordinate them. The wait()\notify()\notifyAll() method in the Object class can be used to communicate between threads about the state of locks of resources. 68) Why are the sleep() and yield() methods of the Thread class static? The sleep() and yield() methods of the Thread class will run on the thread that is currently executing. So it doesn't make sense to call these methods on other threads that are in a waiting state. That's why these methods are static. They can work in the thread that is currently executing and avoid the programmer's mistaken belief that these methods can be called on other non-running threads. 69) How to ensure thread safety? There are many ways to ensure thread safety in Java - synchronization, use atomic concurrent classes, implement concurrent locks, use volatile keywords, use invariant classes and thread-safe classes. 70) Which is the better choice between synchronization method and synchronization block? Synchronous blocks are a better choice because they won't lock the entire object (of course you can also let it lock the entire object). The synchronization method locks the entire object, even if there are multiple unrelated synchronization blocks in the class, which usually causes them to stop executing and need to wait to get the lock on the object. 71) How to create a daemon thread? Use the setDaemon(true) method of the Thread class to setDaemon(true) method to set the thread as a daemon thread. It should be noted that this method needs to be called before calling the start() method, otherwise an IllegalThreadStateException will be thrown. 72) Thread scheduling strategy? (1) Preemptive scheduling strategy The thread scheduling algorithm of the Java runtime system is preemptive. The Java runtime system supports a simple fixed-priority scheduling algorithm. If a thread with a higher priority than any other thread in a runable state enters the ready state, the runtime system will select that thread to run. The new thread with higher priority preempts other threads. However, the Java runtime system does not preempt threads with the same priority. In other words, the Java runtime system is not time-sliced. However, the implementation system based on the Java Thread class may support time-sharing, so do not rely on time-sharing when writing code. When all threads in the ready state in the system have the same priority, the thread scheduler adopts a simple, non-preemptive scheduling sequence. (2) Time slice rotation scheduling strategy Some systems use round-robin scheduling strategies. This scheduling strategy is to assign a certain CPU time from all threads in the ready state to run. After that time, another thread will run. Only when the thread runs, give up the CPU, or enters a blocking state for some reason, the low-priority thread has the opportunity to execute. If two threads with the same priority are waiting for the CPU, the scheduler selects the running thread in a rotating manner. 73) How do you deal with uncatchable exceptions in the thread? Thread.UncaughtExceptionHandler is a new interface in java SE5, which allows us to add an exception handler to each Thread object. |
>>: Top 10 Core Data tools and open source libraries loved by developers
This series of articles mainly discusses the four...
In daily life, have you ever felt snapping or dis...
In 2022, my country's lithium-ion battery ind...
Mixed knowledge, Specially designed to cure confu...
"Imported goods are naturally more expensive...
India's high taxes on imported cars have beco...
Source: Dr. Curious...
With the deepening of the Internet, mobile office...
[[134505]] May 2015 is already halfway through, a...
gossip Lotus root is known as "China's s...
How effective is the anti-addiction "teenage...
Many people know that WeChat is developing a prod...
[[153333]] I've been learning test-driven dev...
In 2019, when many people were lamenting that &qu...
Android 9.0 Pie was officially released a few day...