(Java Intern) punch in 10 interview questions every day -- Java multithreading

  • Approaching the autumn recruitment and preparing for summer internship, I wish you all a little progress every day!
  • This article summarizes the interview questions related to Java multithreading knowledge, which will be updated every day~

1. What are processes, threads and coroutines, and what is the relationship between them?

  • Process: in essence, it is an independently executed program. Process is the basic concept of resource allocation and scheduling by the operating system. The operating system is an independent unit for resource allocation and scheduling.
  • Thread: it is the smallest unit that the operating system can schedule operations. It is included in the process and is the actual operation unit in the process. Each thread can execute multiple tasks in a different system.
  • Coroutine: also known as micro thread, it is a lightweight thread in user mode. Unlike threads and processes, coroutine requires context switching on the system kernel. The context switching of coroutine is determined by the user and has its own context. Therefore, it is a lightweight thread, also known as user level thread, which is called coroutine. A thread can have multiple coroutines, Thread processes are synchronous, while coprocesses are asynchronous. The native syntax of Java does not implement the co process. At present, python, Lua, GO and other languages support it
  • Relationship between the three:
    • A process can have multiple threads, which allows the computer to run two or more programs at the same time. The thread is the smallest execution unit of the process. The scheduling of CPU switches the process and thread. After the process and thread are more, scheduling will consume a lot of CPU, and the thread running on CPU actually runs on threads.

2. Could you tell the difference between concurrency and parallelism and give an example?

  • Concurrent concurrency: one core CPU simulates multiple threads to execute alternately quickly.
  • Parallel parallelism: multi-core CPU, multiple threads can execute at the same time;
    • eg: thread pool!
  • It also refers to handling multiple tasks macroscopically over a period of time. Parallelism means that multiple tasks really run simultaneously at the same time.

give an example:

Concurrent: it's multitasking, listening to classes and watching movies, but CPU There's only one brain, so take turns

Parallel: the shadow part in Naruto. There are multiple you who can do different things

3. What are the ways to implement multithreading in java, what are the differences, and which is more commonly used?

3.1 inherit Thread

  • Inherit the Thread, rewrite the run() method inside, create an instance, and execute the start() method.
  • Advantages: code writing is the simplest and direct operation.
  • Disadvantages: there is no return value. After inheriting one class, you cannot inherit other classes, and the expansibility is poor.
public class ThreadDemo1 extends Thread {
    @Override
    public void run() {
        System.out.println("inherit Thread Implement multithreading, name:"+Thread.currentThread().getName());
    }
}

public static void main(String[] args) {
      ThreadDemo1 threadDemo1 = new ThreadDemo1();
      threadDemo1.setName("demo1");
      // Execute start
      threadDemo1.start();
      System.out.println("Main thread Name:"+Thread.currentThread().getName());
}

3.2 implementation of Runnable interface

  • The custom class implements Runnable, implements the run() method inside, creates a Thread class, passes the implementation object of the Runnable interface as a parameter to the Thread object, and calls the strat() method.
  • Advantages: thread classes can implement multiple interfaces and inherit another class.
  • Disadvantages: there is no return value and cannot be started directly. It needs to be started by constructing a Thread instance.
public class ThreadDemo2 implements Runnable {
    @Override
    public void run() {
        System.out.println("adopt Runnable Implement multithreading, name:"+Thread.currentThread().getName());
    }
}

public static void main(String[] args) {
        ThreadDemo2 threadDemo2 = new ThreadDemo2();
        Thread thread = new Thread(threadDemo2);
        thread.setName("demo2");
    	// start thread execution
        thread.start();
        System.out.println("Main thread Name:"+Thread.currentThread().getName());
}

// lambda expressions are used after JDK8
public static void main(String[] args) {
    Thread thread = new Thread(() -> {
        System.out.println("adopt Runnable Implement multithreading, name:"+Thread.currentThread().getName());
    });
    thread.setName("demo2");
    // start thread execution
    thread.start();
    System.out.println("Main thread Name:"+Thread.currentThread().getName());
}

3.3 implementation of Callable interface

  • Create the implementation class of the Callable interface, implement the call() method, and wrap the Callable object in combination with the FutureTask class to realize multithreading.
  • Advantages: it has return value and high expansibility
  • Disadvantages: Jdk5 will not be supported until later. You need to override the call() method and combine multiple classes, such as FutureTask and Thread
public class MyTask implements Callable<Object> {
    @Override
    public Object call() throws Exception {
        System.out.println("adopt Callable Implement multithreading, name:"+Thread.currentThread().getName());
        return "This is the return value";
    }
}

public static void main(String[] args) {
    	// JDK1.8 lambda expression
        FutureTask<Object> futureTask = new FutureTask<>(() -> {
          System.out.println("adopt Callable Implement multithreading, name:" +
                        			Thread.currentThread().getName());
            return "This is the return value";
        });

     	// MyTask myTask = new MyTask();
		// FutureTask<Object> futureTask = new FutureTask<>(myTask);
        // FutureTask inherits Runnable and can be put into Thread to start execution
        Thread thread = new Thread(futureTask);
        thread.setName("demo3");
    	// start thread execution
        thread.start();
        System.out.println("Main thread name:"+Thread.currentThread().getName());
        try {
            // Get return value
            System.out.println(futureTask.get());
        } catch (InterruptedException e) {
            // Thrown if it is interrupted in the blocking wait
            e.printStackTrace();
        } catch (ExecutionException e) {
            // Exception sent during execution is thrown
            e.printStackTrace();
        }
}

3.4 creating threads through thread pool

  • Customize the Runnable interface, implement the run() method, create a thread pool, call the execution method and pass in the object.
  • Advantages: safety, high performance, reuse threads.
  • Disadvantages: it can only be supported after Jdk5. It needs to be used in combination with Runnable.
public class ThreadDemo4 implements Runnable {
    @Override
    public void run() {
        System.out.println("Through thread pool+runnable Implement multithreading, name:" +
                           Thread.currentThread().getName());
    }
}

public static void main(String[] args) {
    	// Create thread pool
        ExecutorService executorService = Executors.newFixedThreadPool(3);
        for(int i=0;i<10;i++){
            // Thread pool executes thread tasks
            executorService.execute(new ThreadDemo4());
        }
        System.out.println("Main thread name:"+Thread.currentThread().getName());
        // Close thread pool
        executorService.shutdown();
}
  • The commonly used Runnable and the fourth thread pool + Runnable are simple, easy to expand, and high-performance (the idea of pooling).

3.5 what are the differences between runnable and callable threads?

  • Thread is an abstract class that can only be inherited, while Runable and Callable are interfaces that need to implement the methods in the interface.
  • Inherit the Thread and rewrite the run() method. To implement the Runable interface, you need to implement the run() method, while the Callable interface needs to implement the call() method.
  • Thread and Runable have no return value, while Callable has a return value.
  • The class that implements the Runable interface cannot directly call the start() method. It needs to create a new Thread and put the implementation class into the Thread, and then call the start() method through the new Thread instance.
  • The class that implements the Callable interface needs to use FutureTask (put the implementation class into it), put the FutureTask instance into the Thread, and then call the start() method through the new Thread instance. To get the return value, you only need to call the get() method with the help of the FutureTask instance!

4. How many states (life cycle) of threads?

Threads have several states (6)!

public enum State {
    /**
     * Thread newborn state
     */
    NEW,
    
    /**
     * Thread running
     */
    RUNNABLE,
    
    /**
     * Thread blocking state
     */
    BLOCKED,
    
    /**
     * Thread waiting state, dead, etc
     */
    WAITING,
    
    /**
     * The thread is in the timeout waiting state. If it exceeds a certain time, it will no longer wait
     */
    TIMED_WAITING,
    
    /**
     * Thread termination status indicates that the thread has completed execution
     */
    TERMINATED;
}

5. Please talk about the methods related to thread state transition: the difference between sleep/yield/join wait/notify/notifyAll?

Methods under Thread:

  • sleep(): a method belonging to Thread, which allows the Thread to suspend execution, wait for the estimated time before resuming, hand over the CPU usage right, will not release the lock, and sleep with the lock! Enter timeout waiting state time_ Waiting, the end of sleep becomes ready Runnable
  • yield(): a method belonging to Thread thread. It pauses the object of the current Thread, executes other threads, gives up CPU usage rights, and does not release the lock. Similar to sleep(), it allows threads with the same priority to execute in turn, but it does not guarantee rotation,
    • Note: the thread will not enter the BLOCKED state, but will directly become ready Runnable. It only needs to regain the CPU usage right.
  • Join(): a method belonging to Thread. Running and calling this method on the main Thread will make the main Thread sleep without releasing the lock. Let the Thread calling the join() method finish executing first, and then execute other threads. Similar to giving priority to ambulances and police cars!!

Methods under Object:

  • Wait(): a method belonging to Object. When the current thread calls the wait() method of the Object, it will release the lock and enter the waiting queue of the thread. It needs to wake up by notifyAll() or notifyAll() or wait(timeout) time.
  • notify(): a method belonging to Object, which wakes up a single thread waiting on the Object monitor and wakes up randomly.
  • notifyAll(): a method belonging to an Object that wakes up all threads waiting on the Object monitor

Thread state transition flowchart

6. The difference between Thread calling the start() method and calling the run() method

run(): ordinary methods call the run() function and execute in the main thread. There will be no new thread to execute.

start(): a new thread is started. At this time, the thread is in the ready (runnable) state and does not really run. Once the CPU time slice is obtained, the run() method is called to execute the thread task.

7. What are the core attributes of thread pool?

Benefits of using thread pools:

Reuse existing threads, reduce the cost of object creation and destruction, effectively control the maximum number of concurrent threads, improve the utilization rate of system resources, avoid excessive resource competition and congestion, and can be executed regularly, single thread and concurrency control, and configure the rejection policy after too many tasks.

Category:

  • newFixedThreadPool: a fixed length thread pool that can control the maximum concurrent number of threads.
  • newCachedThreadPool: a cacheable thread pool.
  • Newsinglethreadexecution: a singleton thread pool that uses a unique worker thread to execute tasks.
  • newScheduledThreadPool: a fixed length thread pool that supports scheduled / periodic task execution.

[Alibaba coding Specification] thread pools are not allowed to be created using Executors. Why should they be created through ThreadPoolExecutor?

Executors The bottom layer of the created thread pool is also called ThreadPoolExecutor,Just use different parameters, queues, rejection policies, etc. if used improperly, it will cause the problem of resource depletion. Direct use ThreadPoolExecutor Let users know more about the thread pool permission rules and the use of common parameters to avoid risks.

Common thread pool problems:
1.newFixedThreadPool and newSingleThreadExecutor: 
	Queue usage LinkedBlockingQueue,Queue length is Integer.MAX_VALUE,May cause accumulation, resulting in OOM
2.newScheduledThreadPool and newCachedThreadPool:
    The maximum number of threads allowed in the thread pool is Integer.MAX_VALUE,Too many threads may be created, resulting in OOM

The parameters in ThreadPoolExecutor constructor. Can you explain the function of each parameter?

public ThreadPoolExecutor(int corePoolSize,
                          int maximumPoolSize,
                          long keepAliveTime,
                          TimeUnit unit,
                          BlockingQueue<Runnable> workQueue,
                          ThreadFactory threadFactory,
                          RejectedExecutionHandler handler)
  • corePoolSize: the number of core threads. The thread pool will also maintain the minimum number of threads. By default, core threads will always survive. Even if there are no tasks, they will not be controlled by keepAliveTime!
    Pit: when the thread pool is just created, the thread will not start immediately. The thread will not be created until there is a task submission, and the number of threads will gradually reach corePoolSize.

  • maximumPoolSize: the maximum number of thread pool maintenance threads. If it exceeds, it will be blocked!
    Pit: when the core thread is full and the blocking queue is also full, it will judge whether the current number of threads is less than the maximum number of threads, and then decide whether to create a new thread

  • keepAliveTime: the idle timeout of non core threads. After this time, it will be recycled until the number of threads is equal to corePoolSize.

  • Unit: Specifies the unit of keepAliveTime, such as timeunit SECONDS,TimeUnit.MILLISECONDS

  • workQueue: the task queue in the thread pool. Commonly used are ArrayBlockingQueue, LinkedBlockingQueue and SynchronousQueue.

  • threadFactory: the factory used when creating new threads

  • handler: RejectedExecutionHandler is an interface with only one method. The number of threads in the thread pool is greater than maximumPoolSize. There are four processing strategies for rejecting tasks by default:

    • AbortPolicy
    • CallerRunsPolicy
    • DiscardOldestPolicy
    • DiscardPolicy

8. Do you know the rejection policies of thread pool?

  • AbortPolicy: abort policy. The default rejection policy directly throws RejectedExecutionException. The caller can catch this exception and then write his own processing code according to the requirements.

  • Discard policy: discard policy. Do nothing and directly abandon the rejected task.

  • Discard oldest policy: discard the oldest policy. Discarding the oldest task in the blocking queue is equivalent to the next task to be executed in the queue, and then resubmitting the rejected task. If the blocking queue is a priority queue, the "discard oldest" policy will cause the task with the highest priority to be discarded, so it is best not to use this policy together with the priority queue.

  • Callerpolicy: caller policy. Execute the task in the caller thread. The strategy implements a regulation mechanism. The strategy will neither abandon the task nor throw an exception, but return the task to the caller (the main thread calling the thread pool to execute the task). Because it takes a certain time to execute the task, the main thread cannot submit the task for at least a period of time, so that the thread pool has time to process the executing task.

9. Please briefly describe the operation process of a process pool

Picture reference: https://joonwhee.blog.csdn.net/article/details/115364158

10. What methods can be used in Java to ensure thread safety?

  • Locking: such as synchronize/ReentrantLock.
  • Using volatile declaration variables, lightweight synchronization, can not guarantee atomicity (need to be explained).
  • Use thread safe classes, such as atomic class AtomicXXX, etc.
  • Use thread safe collection containers, such as CopyOnWriteArrayList/ConcurrentHashMap, etc.
  • ThreadLocal local private variable / Semaphore semaphore, etc.

The summary interview questions also take a lot of time. The articles will be updated from time to time. Sometimes more than a few articles will be updated a day. If you help you review and consolidate your knowledge points, please support it for three times, and the follow-up will be updated a little bit!

Keywords: Java

Added by tolli on Wed, 09 Feb 2022 04:49:50 +0200