Concurrent programming high frequency interview questions, the more stars behind the question, the higher the probability of appearing in the interview

Recommended reading:

  • Java basic high-frequency interview questions

  • MySQL high frequency interview questions

  • Computer network high-frequency interview questions

  • Java set high frequency interview questions

directory

What is a process? What thread is it? * * *

Thread is the basic unit of processor task scheduling and execution, and process is the basic unit of operating system resource allocation.

Process is a process of program execution, is the basic unit of system operation. A thread is a smaller unit of execution than a process, and a process can contain multiple threads.

Process and thread relationship? (difference) * * *

Definition: thread is the basic unit of processor task scheduling and execution. Processes are the basic unit of operating system resource allocation.

Containment relationships: A process can contain multiple threads.

From the perspective of the Java virtual machine, the runtime data area of the Java virtual machine consists of the heap, method area, virtual machine stack, local method stack, and program counter. Each process is independent of each other, and each process contains multiple threads. The multiple threads contained in each process are not independent of each other. This thread shares the heap and method area of the process, but these threads do not share the virtual machine stack, local method stack, and program counter. That is, multiple threads per process share the heap and method area of the process, and have private virtual machine stacks, local method stacks, and program counters, as shown in the figure. Suppose a process has three threads.

You can see the differences between the following processes and threads in the following aspects:

Memory allocation: The address space and resources between processes are independent of each other. Threads in the same process share the address space and resources (heap and method area) of the threads.

Resource cost: Each process has its own data space, and switching between processes costs a lot. Threads belonging to the same process share the heap and method area, and have private virtual machine stacks, local method stacks, and program counters, making switching between threads less costly.

What’s the difference between parallelism and concurrency? *

Parallelism: Multiple processors processing multiple tasks simultaneously per unit of time.

Concurrency: one processor processes multiple tasks in turn in time slices.

Pros and cons of multithreading (why do you use multithreading and what problems do multithreading cause) * *

Advantages: When a thread enters the wait state or blocks, the CPU can execute other threads first, increasing CPU utilization.

Disadvantages:

  • Context switching: Frequent context switching can affect the execution speed of multiple threads.
  • A deadlock
  • Resource constraints: In concurrent programming, the execution speed of the program is limited by the hardware or software resources of the computer. In concurrent programming, program execution is faster because the parts of the program that are executed in serial are executed concurrently. If the parts that are executed concurrently are still executed in serial because of resource constraints, the program execution will be slower because of context switching and resource scheduling.

Context switching for threads * * *

Even single-core processors support multithreading, and the processor allocates CPU time slices to each thread to achieve this mechanism. The time slice is the amount of execution time that the CPU allocates to each thread. Generally, the time slice is very short, so the processor will keep switching threads.

CPU will pass time slice allocation algorithm to perform a task, the task execution after a time slice will switch to the next task, but before the switch will save the state of a task, even when the next time the switch back to the task load state continue to perform this task, save from the task to in the process of loading is a context switch.

What is the difference between daemon threads and user threads in Java? *

Any Thread can be set as a daemon Thread and a user Thread using thread.setdaemon (bool on), which is true or false. Also, Thread.setdaemon () must be called before Thread.start() or it will throw an exception at runtime.

User thread: Normally used threads are user threads.

Daemon threads: Threads used to service user threads, such as garbage collection threads.

The main difference between daemon threads and user threads is that the Java virtual machine is postlived.

User threads: The Java virtual machine does not terminate until either user thread terminates.

Daemons: How only daemons remain and the Java virtual machine ends.

How do thread deadlocks occur and how can they be avoided

This is important, but it’s also possible to get a code example of a handwritten deadlock during an interview.

Deadlock: When two or more threads compete for each other’s resources without releasing their own resources, all threads block at the same time.

Deadlock conditions:

  • Mutually exclusive condition: a resource can only be occupied by one thread at a time.
  • Request and hold conditions: A thread blocks while requesting occupied resources and holds on to acquired resources.
  • Loop wait condition: When a deadlock occurs, all threads block in an infinite loop.
  • Non-deprivation condition: a thread cannot deprivate the resources it has acquired before using them up. It can only release the resources after using them up.

The main way to avoid deadlocks is to break the conditions under which they occur.

  • Break mutually exclusive conditions: This condition cannot be broken, the lock is used to make them mutually exclusive.
  • Break request and hold conditions: request all resources at once.
  • Break the circular wait condition: request resources in order.
  • Breaking non-deprivation condition: the thread voluntarily abandons the resource it holds when it cannot claim the required resource.

Deadlock with Java implementation, and give a solution to avoid deadlock * *

class DeadLockDemo {
    private static Object resource1 = new Object();
    private static Object resource2 = new Object();

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

        new Thread(() -> {
            synchronized (resource2) {
                System.out.println(Thread.currentThread() + "get resource2");
                try {
                    Thread.sleep(1000); // Thread sleep ensures thread 1 gets resource 1 first
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread() + "waiting get resource1");
                synchronized (resource1) {
                    System.out.println(Thread.currentThread() + "get resource1"); }}},Thread 2 "").start(); }}Copy the code
The Thread (Thread1.5,main]get resource1 Thread[Thread2.5,main]waiting get resource1 Thread1.5,main]waiting get resource2
Copy the code

The main reason for the above code deadlock is that thread 1 acquires resource 1, thread 2 acquires resource 2, thread 1 continues to acquire resource 2 and blocks, thread 2 continues to acquire resource 1 and blocks. The simplest way to solve the problem is the two threads in order to obtain resources, thread thread 1 and 2 are access to resources 1 first, then access to resources 2, whichever thread to obtain resources 1, another thread can have a blocked because of unable to get the thread 1, wait until the first 1 thread to release resources access to resources, another thread for resources 1, This allows the two threads to alternately acquire resources 1 and 2. The code is as follows:

    private static Object resource1 = new Object();
    private static Object resource2 = new Object();

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

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

What’s the difference between deadlocks, live locks, and starvation in Java? *

Live lock: the task or performer is not blocked and the thread keeps trying, failing, trying, failing because some condition has not been met. For example, thread 1 and thread 2 both need to get a resource, but they let other threads get the resource first. Both threads are meek until they can’t get it

The difference between a live lock and a deadlock:

  • Live locks are trying, deadlocks are waiting.
  • Live locks may unlock themselves, deadlocks cannot unlock themselves.

Hunger: A state in which one or more threads are unable to execute because they cannot get the resources they need for any reason. Take the printer to print files as an example. When multiple threads need to print files, the system prints short files first. However, when the printing task of short files continuously appears, the printing task of long files will be postponed all the time, resulting in hunger. Live lock is starvation under the condition of busy wait, which is waiting without entering the waiting state.

Causes of hunger:

  • A high-priority thread consumes the CPU time of a low-priority thread
  • A thread is permanently blocked in a state waiting to enter a synchronized block because other threads can always access the synchronized block before it does.
  • A thread is waiting on an object that is itself in permanent wait completion (such as the object that calls it)wait()Method), because other threads are constantly being woken up.

The difference between deadlock and hunger: Hunger unlocks itself, deadlock does not.

Thread life cycle and state * * *

Thread states aren’t unique, but they’re pretty much the same. See The Art of Concurrent Programming in Java for details.

state
NEW Initial state,Note that it is not called at this pointstart()methods
RUNNABLE Running state, including ready and running states
BLOCKED The blocking state
WAITING Wait state
TIME_WAITING A timeout wait state, unlike a wait state, can return at a specified time
TERMINATED Termination state. The thread is finished running

The thread conversion process is as follows:

What are the ways to create a thread? * * *

  • inheritanceThreadClass creation thread
  • implementationRunnableInterface creation thread
  • useCallableandFutureCreate a thread
  • Use thread pools for exampleExecutorThe framework

Create threads by inheriting Thread, overriding the run() method, and calling the subclass’s start() method in main().

public class ThreadDemo extends Thread {
    @Override
    public void run(a) {
        System.out.println(Thread.currentThread().getName() + "The run() method is executing"); }}Copy the code
public class TheadTest {
    public static void main(String[] args) {
        ThreadDemo threadDemo = new ThreadDemo(); 	
        threadDemo.start();
        System.out.println(Thread.currentThread().getName() + "Main () method completes execution"); }}Copy the code

Output result:

main main(a)The thread-0 method endsrun(a)Method executingCopy the code

** First create a RunnableDemo class that implements the Runnable interface, overriding the run() method; Create RunnableDemo, an instance object of class RunnableDemo, and create a Thread object with RunnableDemo as an argument. Call the start() method of the Thread object.

public class RunnableDemo implements Runnable {
    @Override
    public void run(a) {
        System.out.println(Thread.currentThread().getName() + "The run() method is executing"); }}Copy the code
public class RunnableTest {
    public static void main(String[] args) {
        RunnableDemo  runnableDemo = new RunnableDemo ();
        Thread thread = new Thread(runnableDemo);
        thread.start();
        System.out.println(Thread.currentThread().getName() + "Main () method completed");
}
Copy the code

Output result:

main main(a)Thread-0 is executedrun(a)Method in executionCopy the code

1. Create the Callable interface implementation class CallableDemo and override the Call () method. 2. Create a FutureTask object with an instantiated object of class CallableDemo as a parameter. 3. Create a Thread object with FutureTask as the parameter. 4. Call the start() method of the Thread object.

class CallableDemo implements Callable<Integer> {

    @Override
    public Integer call(a) {
        System.out.println(Thread.currentThread().getName() + "Call () method in execution");
        return 0; }}class CallableTest {

    public static void main(String[] args) throws ExecutionException, InterruptedException {
        FutureTask<Integer> futureTask = new FutureTask<Integer>(new CallableDemo());
        Thread thread = new Thread(futureTask);
        thread.start();
        System.out.println("Return result" + futureTask.get());
        System.out.println(Thread.currentThread().getName() + "Main () method completed"); }}Copy the code

Output result:

Thread-0The call() method returns results from execution0
main main(a)Method execution completeCopy the code

Use thread pools for example by using the Executor Framework: Exector Provides the following thread pools:

  • newCachedThreadPoolCreate a cacheable thread pool. If the length of the thread pool exceeds the processing requirement, you can recycle idle threads flexibly, or create a new thread if none is available.
  • newFixedThreadPoolCreate a fixed-length thread pool that controls the maximum number of concurrent threads, and the excess threads wait in the queue.
  • newScheduledThreadPoolCreate a fixed – length thread pool to support scheduled and periodic task execution.
  • newSingleThreadExecutorCreate a single threaded thread pool that uses only one worker thread to execute tasks, ensuring that all tasks are executed in the specified order.

The following uses creating a thread pool of fixed length as an example.

class ThreadDemo extends Thread {

    @Override

    public void run(a) {

        System.out.println(Thread.currentThread().getName() + "In process"); }}class TestFixedThreadPool {

        public static void main(String[] args) {

        // Create a reusable thread pool with a fixed number of threads

        ExecutorService pool = Executors.newFixedThreadPool(2);

        Thread objects implement the Runnable interface

        Thread t1 = new ThreadDemo();

        Thread t2 = new ThreadDemo();

        Thread t3 = new ThreadDemo();

        Thread t4 = new ThreadDemo();

        Thread t5 = new ThreadDemo();

        // Put the thread into the pool for execution

        pool.execute(t1);

        pool.execute(t2);

        pool.execute(t3);

        pool.execute(t4);

        pool.execute(t5);

        // Close the thread poolpool.shutdown(); }}Copy the code

Output result:

pool-1-thread-2Description Pool - is being executed1-thread-1Description Pool - is being executed1-thread-1Description Pool - is being executed1-thread-2Description Pool - is being executed1-thread-1Being performedCopy the code

What’s the difference between runnable and callable? * * *

Similarities:

  • Both are interfaces
  • Both need to be calledThread.startStarting a thread

Difference:

  • The core of Callable iscall()Method to allow a return value,runnableIs the core ofrun()Method with no return value
  • call()Method can throw an exception, butrun()Method is not
  • callableandrunnableCan be applied toexecutors.threadClass only supportrunnable

What is the difference between run() and start() for a thread? * * *

  • Threads are routed throughThreadObject corresponding to the methodrun()To complete its operation, while the thread is started throughstart()Method is executed.
  • run()Methods can be called repeatedly,start()Method can only be called once

Why is the run() method executed when the start() method is called instead of the run() method directly? * * *

The start() method is used to start the thread, making it truly multithreaded, without waiting for the run() body to finish executing. A Thread is started by calling the start() method of the Thread class. The Thread is in a ready (runnable) state, but is not running. As soon as the CPU slice is available, the run() method is executed. The thread terminates when the run() method finishes running.

Run () method is a common way of class, if direct call run method, this thread is still only the main thread in the program, the program execution path or there is only one, or to order, or to wait for the run () method body after the execution to continue to execute the following code, so that no writer threads.

A call to the start() method can start a thread, while the run() method is just a normal method in the Thread class. Direct calls to the run() method are still executed in the main thread.

Thread synchronization and thread scheduling related method issues

What are the methods associated with thread synchronization and thread scheduling? * * *

  • Wait () : to cause a thread to wait(block) and release the lock on its holding object;

  • Sleep () : Puts the current thread into sleep for a specified number of milliseconds, suspending execution and handling InterruptedException.

  • Notify () : Wakes up a thread that is in the wait state. The JVM determines which thread to wake up, regardless of the priority.

  • NotifyAll () : Wakes up all threads in the waiting state. Instead of locking the object to all threads, notifyAll() makes them compete, and only the thread that obtained the lock enters the ready state.

  • Jion () : Like the sleep() method, jion() is a interruptible method. Calling join() in one thread causes the current thread to suspend until the thread executing the join() method terminates. For example, if thread B calls thread A’s join() method, thread B blocks until thread A terminates or reaches A specified time.

  • Yield () : Indicates that the scheduler is willing to give up the current CPU resource, causing the current thread to switch from the RUNNING state to the RUNABLE state.

What is the difference between a thread’s sleep() method and its yield() method? * * *

  • sleep()Method causes the current thread to pause for a specified amount of time without consuming a CPU slice.
  • sleep()Causing the thread to block,yield()The CPU is only prompted, and if the CPU does not ignore the prompt, the thread context will be switched to the ready state.
  • sleep()Must complete the given sleep time,yield()Not necessarily.
  • sleep()InterruptedException needs to be thrown, whileyield()Method does not need to throw an exception.

What is the difference between sleep() and wait()? * * *

Similarities:

  • wait()Methods andsleep()Methods can cause a thread to enter a blocking state.
  • wait()andsleep()Methods are interruptible methods and receive interrupt exceptions after being interrupted.

Difference:

  • wait()Is a method of Object,sleep()Is the method of Thread.
  • wait()Must be done in a synchronous method,sleep()Methods don’t need to.
  • Threads execute in synchronous methodssleep()Method does not release the monitor lock, whilewait()Method releases the monitor lock.
  • sleep()The method actively exits the block after a short sleep, whilewait()Methods that do not specify a wait time need to be interrupted by other threads to exit the block.

Is wait() normally used in loop blocks or if blocks? * * *

It is explicitly required in the OFFICIAL JDK documentation to be used in loops otherwise false awakenings are possible. Examples of code given in the official documentation are as follows:

synchronized(obj){
    while(<condition does not hold>){
         obj.wait();
    }
    // Execute the business logic when the condition in the while is satisfied
}
Copy the code

If I replace while with if,

synchronized(obj){
    if(<condition does not hold>){
         obj.wait();
    }
    // Execute the business logic when the condition in the while is satisfied
}
Copy the code

When the thread is woken up, it is possible that the condition in if() is no longer met and a false wake occurs.

What are the methods of thread communication? * * *

  • Locks and synchronization
  • wait()/notify()ornotifyAll()
  • A semaphore
  • The pipe

Why are wait(), notify(), and notifyAll() defined in Object and not in Thread? * *

When these methods operate the synchronous thread, they must identify the lock of the thread they operate on. Only the waiting thread on the same lock can be awakened by notify() or notifyAll() on the same lock, but cannot be awakened on the threads in different locks. That is to say, the waiting and waking must be the same lock. The lock can be any Object, so methods that can be called by any Object are defined in the Object class.

If wait(), notify(), and notifyAll() are defined in Thread classes, some difficult problems arise. For example, how can one Thread hold multiple locks? How do I determine which lock a thread is waiting on? Since it is the current thread that is waiting for the lock of an Object, it should be done by manipulating the Object rather than manipulating the thread. Object is the parent of all objects, so it is best to define these three methods in Object.

Why do wait(), notify(), and notifyAll() have to be called in synchronized methods or synchronized blocks? * *

Because wait() suspends the object holding the lock, notify() or notifyAll() wakes the object waiting for the lock. So wait(), notify(), and notifyAll() all require the thread to hold the lock object and therefore need to be called in a synchronized method or synchronized block.

Why are the Thread class’s sleep() and yield() methods static? *

Sleep () and yield() are both called by the executing thread, and it makes no sense for threads that are already blocking or waiting to call this method, so they are static.

How do I stop a running thread? * *

  • Interrupts:InterruptMethod to interrupt thread
  • usevolatile booleanFlag bit to stop thread: Sets one in the threadbooleanFlag bit, used simultaneouslyvolatileThe modifier ensures visibility by constantly reading this value in the thread, which can be modified elsewherebooleanValue.
  • usestop()Method to stop the thread, but the method has been deprecated. Because threads cannot save data before stopping, data integrity issues can occur.

How do I wake up a blocked thread? * *

Threads can be woken up if they are blocked by wait(), sleep(), join(), yield(), and so on. Threads cannot be woken up if they are BLOCKED by IO because IO is operating system level and Java code cannot touch the operating system directly.

  • wait()Available:notify()ornotifyAll()Method wake up.
  • sleep()Call this method and the thread will block for a specified amount of time. When the specified amount of time has passed, the thread will get the CPU time slice again and wake up.
  • join(): the current thread A calls another thread Bjoin()Method, the current thread goes to the blocking state of A, until the completion of thread B, thread A from the blocking state to the executable state.
  • yield(): causes the current thread to drop the CPU slice, but can get the CPU slice again at any time to activate.

How does Java implement communication and collaboration between two threads? * *

  • syncrhoizedOf the locked threadObjectOf the classwait()/notify()/notifyAll()
  • ReentrantLockClass of the thread that holds the lockConditionOf the classawait()/signal()/signalAll()
  • Inter-thread communication through pipes: 1) byte stream; 2) Character stream, where one thread sends data to the output pipe and another thread reads data from the input pipe.

Which works better, synchronized methods or synchronized method blocks? * *

Synchronized blocks are better because they lock more flexibly, locking only the object in the block that needs to be locked, whereas synchronized methods lock the entire object.

What is thread synchronization? What is thread mutexes? How did they do it? * * *

  • The mutual exclusion of threads means that a resource can only be accessed by one visitor, which is unique and exclusive. But the order in which visitors access resources is out of order.
  • Thread synchronization refers to the sequential access of visitors to resources on the basis of mutual exclusion.

Thread synchronization implementation method:

  • Synchronized methods
  • Synchronized code block
  • wait()andnotify()
  • Use volatile for thread synchronization
  • Thread synchronization using a reentrant lock
  • Use local variables for thread synchronization
  • Use blocking queues for thread synchronization

How to ensure the safe running of threads in Java programs? * * *

Thread safety is mainly reflected in atomicity, visibility and order.

  • Atomicity: The ability of one or more operations to be performed without interruption by the CPU. Atomicity issues with thread switching.

  • Visibility: Changes made by one thread to a shared variable can be immediately seen by another thread. Visibility issues caused by caching.

  • Orderliness: The order in which a program is executed is the order in which the code is executed. Order problems with compiler optimization.

Solutions:

  • Atomicity issue: JDK availableAtomicAtomic class at the beginning,synchronized,LOCKTo solve the
  • Visibility issues: Availabilitysynchronized,volatile,LOCKTo solve the
  • Order problem: availabilityHappens-BeforeRules to solve

Which thread calls the constructor, static block of the thread class? *

The thread constructor, the static block, is called by the thread of the new class, while the code inside the run() method is called by the thread itself.

A classic example:

If a thread Thread1 is new in main(), the constructor and static block of Thread1 are called by the main thread, and the run() method in Thread1 is called by itself.

If a thread Thread2 is new in Thread1, the constructor and static block of Thread2 are called by Thread1, and the run() method in Thread2 is called by itself.

What happens when a thread runs an exception? *

Throwable in Java is divided into exceptions and errors. Exceptions are classified as runtime and non-runtime exceptions. Runtime exceptions can be left unhandled, and code can be compiled, but an error will be reported at run time. Non-runtime exceptions must be handled or the code will not compile. Error code occurs directly

What exceptions can be caused by too many threads? *

  • Consumes more memory and CPU
  • Frequent context switches

Search the public account zhang on wechat, reply to the interview manual, and get more frequent interview questions PDF version and more interview materials.