105 Java interview questions and answers (more than 50,000 words of eight-part essay)

Table of contents

1. Java Basics

1.What is Java?

Java is an object-oriented programming language developed by Sun Microsystems and later acquired by Oracle Corporation. Java is cross-platform and can run on different operating systems. The Java language has good readability, portability, scalability and reliability.

2.What are the data types in Java?

Data types in Java include basic data types and reference data types. Basic data types include: byte, short, int, long, float, double, char and boolean; reference data types include: classes, interfaces, arrays, enumerations and annotations, etc.

3. What is autoboxing and unboxing?

Autoboxing and unboxing are new features in Java 5. Autoboxing refers to automatically converting basic data types into corresponding packaging types, and unboxing refers to automatically converting packaging types into corresponding basic data types. For example:

Integer i = 10; // 自动装箱
int j = i; // 自动拆箱

4. What are generics?

Generics are a new feature in Java 5 that make code more flexible and safer. By using generics, you can check type safety at compile time and avoid type conversion errors at run time. For example:

List<String> list = new ArrayList<String>();

5. What is reflection?

Reflection is a mechanism in Java that can dynamically obtain class information and call methods and properties in the class while the program is running. Reflection allows the program to dynamically create objects, call methods, obtain properties, etc. as needed during runtime. For example:

Class<?> clazz = Class.forName("com.example.User");
Object obj = clazz.newInstance();
Method method = clazz.getMethod("getName");
String name = (String) method.invoke(obj);

6. What is an exception?

Exceptions are an error mechanism in Java that are used to handle abnormal situations that occur in programs. Exceptions in Java are divided into checked exceptions and unchecked exceptions. Checked exceptions need to be declared in the method signature, and the caller must handle it or throw an exception; unchecked exceptions do not need to be declared in the method signature and can be thrown anywhere. For example:

try {
    
    
    int result = 1 / 0;
} catch (Exception e) {
    
    
    e.printStackTrace();
}

7. What is a collection?

A collection is a data structure in Java used to store a set of objects. Collections in Java are divided into three types: List, Set and Map. List is used to store ordered elements, which can be repeated; Set is used to store unordered elements, which cannot be repeated; Map is used to store key-value pairs, and the keys cannot be repeated.

8. What is serialization?

Serialization saves the state of an object to a file or network for subsequent restoration. Serialization in Java uses ObjectOutputStream for object serialization and ObjectInputStream for object deserialization. Serialization can be used in scenarios such as data persistence and remote communication.

9.What is multithreading?

Multithreading refers to running multiple threads simultaneously in a process, and each thread can perform different tasks independently. Multithreading in Java is implemented using the Thread class and the Runnable interface. Multi-threading can improve program concurrency and efficiency, but it can also bring thread safety issues.

10.What is synchronized?

synchronized is a synchronization mechanism in Java that is used to ensure the mutual exclusivity and visibility of multiple threads' access to shared resources. The synchronized keyword can be used in methods and code blocks to ensure thread synchronization. synchronized was optimized in Java 5 and introduced the concept of locks, which can avoid problems such as deadlock and starvation.

2. Java object-oriented

11.What is object-oriented?

Object-oriented is a programming idea that abstracts things in the real world into objects and completes program design through interactions between objects. Object-oriented has features such as encapsulation, inheritance and polymorphism, which can improve program reusability and scalability.

12. What is encapsulation?

Encapsulation is a basic concept in object-oriented, which is used to hide the implementation details of objects and provide a unified interface for external use. Encapsulation can protect the state of the object from outside interference, while also making the code clearer and easier to maintain.

13.What is inheritance?

Inheritance is a basic concept in object-oriented and is used to achieve code reuse and extension. Inheritance allows subclasses to inherit the properties and methods of the parent class, and to modify or extend the parent class's behavior by overriding or overriding it. Inheritance can reduce code duplication and improve code maintainability and scalability.

14.What is polymorphism?

Polymorphism is a basic concept in object-oriented that allows different types of objects to respond differently to the same message. Polymorphism can be achieved through inheritance and interfaces. Polymorphism increases code flexibility and scalability.

15.What is an abstract class?

An abstract class is a class that cannot be instantiated and is used to provide a common template for subclasses. Subclasses can inherit the abstract class and implement the abstract methods in it. Abstract classes can be used to standardize the design of code and improve the maintainability and scalability of the code.

16.What is an interface?

An interface is an abstract class that defines a set of methods but does not implement them. It can be used to standardize the design of the code and improve the maintainability and scalability of the code. Interfaces can be implemented by classes, and a class can implement multiple interfaces. Interfaces can be used to achieve polymorphism and decoupling.

17.What is overloading?

Overloading refers to defining multiple methods in a class. These methods have the same name but different parameter lists. Different methods can be selected based on different parameter types or number of parameters. Overloading improves code flexibility and reusability.

18. What is rewriting?

Overriding means defining a method in a subclass with the same name as the parent class, and the parameter list and return value type of the method are the same. You can modify or extend the method of the parent class. Rewriting can achieve polymorphism and improve code scalability and maintainability.

19.What is the super keyword?

super is a keyword that can be used to call methods and properties of the parent class in the subclass. Using the super keyword enables code reuse and extension.

20.What is this keyword?

this is a keyword that can be used to refer to the current object in a class and can be used to access the properties and methods of the current object. Using the this keyword can improve the readability and maintainability of your code.

3. Java collection framework

21.What is a collection framework?

The collection framework is a class library in Java used to store and operate a set of objects, including common collection types such as List, Set, and Map. The collection framework provides a common set of interfaces and classes that enable efficient data operations.

22.What is a List?

List is an ordered collection in the collection framework that can store repeated elements. List provides a set of methods for operating sequences, elements can be accessed through indexes, and data structures such as stacks, queues, and linked lists can be implemented.

23.What is Set?

Set is an unordered collection in the collection framework that does not allow storing duplicate elements. Set provides a set of methods for operating sets, which can implement set operations such as intersection, union, and difference.

24.What is Map?

Map is a collection of key-value pairs in the collection framework, each element contains a key and a value. Map provides a set of methods for operating key-value pairs, which can implement data structures such as dictionaries and hash tables.

25.What is an Iterator?

Iterator is an interface in Java for traversing the elements of a collection. The elements in the collection can be accessed sequentially through an iterator. Iterator provides a set of methods for traversing collections, including hasNext, next, remove, etc.

26.What is the Comparable interface?

Comparable is an interface used to compare object sizes in Java. Objects that implement the Comparable interface can be compared through the compareTo method. The comparison rules are determined by the object's implementation, allowing for a natural ordering of objects.

27.What is the Comparator interface?

Comparator is an interface used to compare object sizes in Java. By implementing the compare method of the Comparator interface, you can customize the comparison rules of objects and achieve unnatural sorting of objects.

28.What is the difference between ArrayList and LinkedList?

ArrayList and LinkedList are both implementations of the List interface. Their difference lies in the efficiency of data structure and operations. ArrayList uses arrays internally to store elements, and elements can be accessed through indexes, but inserting and deleting elements requires moving subsequent elements; LinkedList uses linked lists internally to store elements, and elements can be quickly inserted and deleted, but accessing elements requires traversing the linked list.

29.What is the difference between HashSet and TreeSet?

HashSet and TreeSet are both implementations of the Set interface. Their difference lies in the way elements are stored and the ordering of elements. HashSet uses a hash table internally to store elements, which can quickly find elements, but does not guarantee the order of the elements; TreeSet uses a red-black tree internally to store elements, which can ensure that the elements are stored in order according to the sorting rules.

30.What is the difference between HashMap and TreeMap?

HashMap and TreeMap are both implementations of the Map interface. Their difference lies in the way elements are stored and the ordering of elements. HashMap internally uses a hash table to store key-value pairs, which can quickly find the value corresponding to the key, but does not guarantee the order of the key-value pairs; TreeMap internally uses a red-black tree to store key-value pairs, which can be stored in an orderly manner according to the sorting rules of the keys. Key-value pairs.

4. Java multithreading

31.What is a thread?

A thread is the smallest unit of program execution and an independent execution flow in a process. It can execute multiple threads at the same time to achieve multi-tasking.

32.What is a process?

A process is an instance of an executing program, the basic unit of operating system resource allocation, and can contain multiple threads.

33.What is concurrency?

Concurrency means that multiple tasks are executed alternately on the same processor during the same time period to achieve multi-tasking.

34.What is synchronization?

Synchronization refers to the use of lock mechanisms to ensure the access sequence of shared resources in multi-thread programming and avoid data inconsistencies.

35.What is asynchronous?

Asynchronous means that in multi-threaded programming, you can start executing the next task without waiting for the completion of the previous task, which can improve the efficiency and response speed of the program.

36.What is a thread pool?

Thread pool is a mechanism for managing and reusing threads, which can improve the performance and resource utilization of multi-threaded programs.

37.What is deadlock?

Deadlock refers to a situation where two or more threads are waiting for each other to release resources, causing the program to be unable to continue executing.

38.What is thread safety?

Thread safety means that when multiple threads access shared resources, it ensures that the operations of shared resources are atomic, visible, and orderly, and avoids data inconsistency.

39.What is atomicity?

Atomicity means that operations on shared resources are indivisible. Either all operations succeed or all operations fail to avoid data inconsistency.

40. What is visibility?

Visibility means that when multiple threads access shared resources, it ensures that operations on shared resources are visible to other threads to avoid data inconsistencies.

41.What is orderliness?

Orderliness means that operations on shared resources are performed in a certain order to ensure the correctness of operations and avoid data inconsistencies.

42.What is the synchronized keyword?

synchronized is the keyword used to implement thread synchronization in Java, which can ensure that the operations of shared resources are atomic, visible, and orderly.

43.What is the function and usage of synchronized?

The role of synchronized is to ensure thread safety when multiple threads access shared resources. It can be used in methods and code blocks. Using synchronized in a method means locking the entire method, and only one thread can execute the method; using synchronized in a code block means locking the shared resource in the code block, and only one thread can access the shared resource.

44.What is the difference between synchronized and Lock?

synchronized is the keyword used to implement thread synchronization in Java, and Lock is the interface used to implement thread synchronization in Java. The difference between them lies in the implementation method and function. synchronized is implemented at the JVM level, which can automatically release locks and is easy to use, but does not support advanced functions; Lock is implemented at the Java level, which requires manual release of locks and can support advanced functions such as fair locks, read-write locks, and reusable locks. Lock in etc.

45.What is a reentrant lock?

Reentrant lock is a lock mechanism that supports repeated acquisition of locks, that is, the same thread can acquire the same lock multiple times without deadlock. Both synchronized and ReentrantLock in Java are reentrant locks.

46.What is a read-write lock?

Read-write lock is a special lock mechanism that can control concurrent access of read operations and write operations respectively, improving the concurrency performance of the program. ReentrantReadWriteLock in Java is a read-write lock.

47.What is the volatile keyword?

Volatile is a keyword used to implement thread synchronization in Java. It can guarantee the visibility and ordering of shared variables, but it cannot guarantee atomicity because it can only guarantee that the operation of a single variable is atomic.

48.What is the difference between volatile and synchronized?

Both volatile and synchronized can be used to implement thread synchronization, but their functions and usage are different. Volatile is mainly used to ensure the visibility and orderliness of shared variables, while synchronized is mainly used to ensure atomicity, visibility and orderliness when multiple threads access shared resources. In addition, volatile cannot guarantee atomicity, but synchronized can.

49.What is a thread pool?

Thread pool is a technology for managing threads. It can create a certain number of threads in advance and assign tasks to idle threads for processing when tasks arrive, thereby avoiding the overhead of frequently creating and destroying threads.

50.How to create a thread pool in Java?

You can use the ThreadPoolExecutor class in Java to create a thread pool, and create different types of thread pools by specifying the number of core threads, the maximum number of threads, queue type, rejection policy and other parameters.

51.What is the number of core threads in the thread pool?

The number of core threads in the thread pool refers to the minimum number of threads maintained by the thread pool when no tasks need to be executed. The number of core threads is usually set to the maximum number of threads the system can support.

52.What is the maximum number of threads in the thread pool?

The maximum number of threads in the thread pool refers to the maximum number of threads that can exist simultaneously in the thread pool. Tasks that exceed the maximum number of threads will enter the waiting queue or be refused execution.

53.What is a thread pool queue?

The thread pool's queue is a container used to store tasks. It can be a blocking queue or a non-blocking queue. When all threads in the thread pool are processing tasks, new tasks will be stored in the queue waiting to be executed.

54.What is the rejection policy of the thread pool?

The thread pool's rejection policy refers to how newly submitted tasks are handled when the queue in the thread pool is full and new threads cannot be created. Common rejection policies include: AbortPolicy (throws an exception directly), CallerRunsPolicy (executes the task in the calling thread), DiscardOldestPolicy (discards the oldest task in the queue), and DiscardPolicy (discards new tasks).

55.What are the thread pools in Java?

Commonly used thread pools in Java are: FixedThreadPool, CachedThreadPool, SingleThreadPool and ScheduledThreadPool.

56.What is the Fork/Join framework?

The Fork/Join framework is a parallel computing framework introduced in Java 7 to solve the problem of parallel processing of decomposable tasks. Its core idea is to split a large task into multiple small tasks, assign them to multiple threads for execution, and finally merge the results. The Fork/Join framework can automatically determine when to use multi-threads for calculations and when to use single-threads for calculations based on task size and computing power, thereby achieving optimal calculations.

57.What are the locking mechanisms in Java?

Lock mechanisms in Java include synchronized, ReentrantLock, ReadWritelock, etc.

58.What is the difference between synchronized and ReentrantLock?

synchronized and ReentrantLock are both mechanisms used to achieve thread synchronization. Their functions and usage are similar, but there are some differences. synchronized is a built-in lock in Java and is very simple to use, but it can only implement simple synchronization scenarios and has poor performance when lock competition is fierce. ReentrantLock is an explicit lock in Java. It is relatively complex to use, but it can implement more complex synchronization scenarios and perform better when lock competition is fierce.

59.What is CAS (Compare and Swap) operation?

CAS (Compare and Swap) operation is an atomic operation used to implement lock-free concurrency algorithms. The CAS operation will first compare whether the value in the memory is the same as the expected value. If they are the same, the new value will be written into the memory, otherwise no operation will be performed.

60.How is the CAS operation implemented in Java?

CAS operations in Java are implemented through the sun.misc.Unsafe class. The Unsafe class provides some low-level operations, including atomic operations, memory management, thread synchronization, etc.

61.What is AQS (AbstractQueuedSynchronizer)?

AQS (AbstractQueuedSynchronizer) is a framework in Java for implementing locks and synchronizers. It provides some basic synchronization operations, such as acquire and release, and also allows developers to customize synchronizers.

62.What is CountDownLatch?

CountDownLatch is a thread synchronization tool that blocks one or more threads until other threads complete a series of operations before continuing. It is implemented through a counter. The initial value of the counter can be set to any value. Whenever a thread completes a certain operation, the counter value will be reduced by 1. When the counter value is reduced to 0, the blocked thread will be wake.

63.What is CyclicBarrier?

CyclicBarrier is a thread synchronization tool that allows multiple threads to wait at a certain barrier point until all threads reach that point before they can continue execution. Unlike CountDownLatch, CyclicBarrier's counter is automatically reset and can be used cyclically. When all threads reach the barrier point, CyclicBarrier will automatically unblock the state, and then all threads can continue execution.

64.What is Semaphore?

Semaphore is a thread synchronization tool that can control the number of threads accessing a resource at the same time. Semaphore maintains a license (Permit) counter internally. When a thread needs to access a resource protected by Semaphore, it needs to obtain a license first. When the license counter reaches 0, the thread requesting the license will be blocked. .

65.What is an Exchanger?

Exchanger is a thread synchronization tool that allows data to be exchanged between two threads. When a thread calls the Exchanger's exchange() method, it is blocked until the other thread also calls the exchange() method, and then data is exchanged between the two threads, and execution continues.

66.What is a thread pool?

The thread pool is a mechanism for managing threads. It can create some threads in advance and maintain a task queue. When a new task needs to be executed, the task will be added to the task queue, and then the idle thread will complete the task. Perform tasks. Using a thread pool can avoid the overhead of repeatedly creating and destroying threads, thereby improving system performance.

67. How does the thread pool work?

The thread pool works as follows:

  • Initialize the thread pool, create a certain number of threads, and put them in a waiting state.
  • When a new task arrives, the thread pool adds the task to the task queue.
  • The idle thread will take out the task from the task queue and execute it until the task queue is empty.
  • If the task queue is empty, the idle thread will continue to wait for new tasks to arrive.
  • If the task queue is full and all threads are executing tasks, the thread pool will handle the tasks according to the configured strategy, such as blocking, abandoning, etc.

68. What is the difference between the number of core threads and the maximum number of threads in the thread pool?

The number of core threads in the thread pool is the minimum number of threads in the thread pool. Even if there are no tasks in the thread pool, the core threads will always exist until the thread pool is closed. The maximum number of threads is the maximum number of threads in the thread pool. When the number of tasks exceeds the number of core threads, the thread pool will create new threads to process tasks until the number of threads reaches the maximum number of threads.

69.What are the task queues in the thread pool?

Task queues in the thread pool include the following:

  • Direct submission to the queue: Submit the task directly to the thread in the thread pool for execution. If there are no idle threads in the thread pool, a new thread will be created to execute the task.
  • Bounded queue: can store a certain number of tasks. When the number of tasks reaches the upper limit of the queue, the thread pool will reject new tasks.
  • Unbounded queue: can store any number of tasks. When the number of tasks exceeds the number of core threads, the thread pool will create new threads to process the tasks.

70.What are the rejection strategies in the thread pool?

Denial strategies in thread pools include the following:

  • AbortPolicy: Throw an exception directly to prevent the system from working normally.
  • CallerRunsPolicy: Only use the caller's thread to perform tasks.
  • DiscardOldestPolicy: Discard the oldest task in the queue and execute the current task.
  • DiscardPolicy: Do not process, discard the task directly.

71.What are the parameters in the thread pool?

Parameters in the thread pool include the following:

Number of core threads: The minimum number of threads in the thread pool.

Maximum number of threads: The maximum number of threads in the thread pool.

Task queue: A queue that stores tasks, which can be a direct submission queue, a bounded queue, an unbounded queue, etc.

Rejection strategy: The processing strategy when the task cannot be processed.

The survival time of idle threads: When the idle time of a thread in the thread pool exceeds this value, the thread will be recycled.

72. What is the difference between the execute() and submit() methods in the thread pool?

The execute() method is used to submit a Runnable type task, and the submit() method is used to submit a Callable type task. It returns a Future object that can be used to obtain the execution result of the task. In addition, the submit() method also supports using Future objects to control the execution of tasks, such as canceling tasks, waiting for task completion, etc.

73.What is FutureTask?

FutureTask is a cancelable asynchronous computing task that implements the Future interface. It can wrap a Callable or Runnable object and provide a get() method to obtain the task execution results. When the task execution is completed, the get() method will return the task execution result. If the task has not been completed, it will block and wait for the task execution to be completed.

74.What is CompletionService?

CompletionService is an extension interface of Executor, which can put completed tasks into a blocking queue, so that completed tasks can be easily obtained. CompletionService can be used to improve task execution efficiency and throughput, especially when processing a large number of tasks. Tasks can be assigned to multiple threads for concurrent execution, and then the completed task results can be obtained through CompletionService.

75.What is the Fork/Join framework?

The Fork/Join framework is a parallel processing framework that can split a large task into several small tasks, execute them in parallel, and finally merge the results. The Fork/Join framework can take advantage of multi-core CPUs to improve task execution efficiency and throughput.

76.What are the core components of the Fork/Join framework?

The core components of the Fork/Join framework include the following:

  • ForkJoinTask: Represents a Fork/Join task, which can be a large task or a small subtask.
  • ForkJoinPool: Represents a Fork/Join thread pool, used to manage and execute Fork/Join tasks.
  • WorkQueue: Represents a task queue, used to store Fork/Join tasks.
  • ForkJoinWorkerThread: Represents a worker thread used to perform Fork/Join tasks.

77.What are the functions of the compute() method and fork() method in ForkJoinTask?

The compute() method is used to execute the logic of the Fork/Join task. It will split the task into several small subtasks and submit these subtasks to the ForkJoinPool for execution. If the task can be executed directly, the logic of the task can also be executed directly in the compute() method without splitting the task.

The fork() method is used to split a large task into several small subtasks, and then submit these subtasks to ForkJoinPool for execution. The fork() method creates a new ForkJoinTask object, representing the split subtasks, and then allocates the subtasks to idle worker threads for execution through the work-stealing algorithm of ForkJoinPool.

78.What is the work-stealing algorithm of ForkJoinPool?

ForkJoinPool's work-stealing algorithm is a scheduling algorithm based on task stealing. Each worker thread has a task queue to store tasks to be executed. When a thread's task queue is empty, it can steal a task from the task queue of another thread to execute. The stolen tasks should be the tasks recently added to the queue, which can improve task execution efficiency and throughput.

79.What is thread safety?

Thread safety means that in a multi-threaded environment, the program can be executed correctly without concurrency problems such as data competition. Thread-safe programs can be accessed by multiple threads at the same time without causing data inconsistencies and erroneous results.

80.What is thread unsafe?

Thread unsafety means that in a multi-threaded environment, a program may encounter concurrency problems such as data competition, causing the program to fail to execute correctly or produce erroneous results. Thread-unsafe programs are not suitable for being accessed by multiple threads at the same time, and synchronization measures need to be taken to avoid concurrency problems.

81.What is thread synchronization?

Thread synchronization refers to coordinating and controlling access to shared resources in a multi-threaded environment to ensure that operations between multiple threads can be executed correctly. The purpose of thread synchronization is to ensure thread safety and data consistency.

82. How to achieve thread synchronization?

Thread synchronization can be achieved in the following ways:

  • synchronized keyword: Use the synchronized keyword to achieve synchronous access to shared resources, which can avoid concurrency problems caused by multiple threads accessing shared resources at the same time.
  • Lock interface: Through the Lock interface and related implementation classes to achieve synchronous access to shared resources, more flexible and fine-grained synchronization control can be achieved.
  • volatile keyword: The volatile keyword is used to ensure the visibility and orderliness of shared variables, which can avoid inconsistent results from multiple threads operating on shared variables.
  • Atomic classes: By using atomic classes to implement atomic operations on shared variables, you can ensure that operations on shared variables between multiple threads are thread-safe.

83.What is the difference between the synchronized keyword and the Lock interface?

Both the synchronized keyword and the Lock interface can implement synchronous access to shared resources, but there are the following differences between them:

  • Usage: synchronized implements synchronous access through keywords, while the Lock interface implements synchronous access by instantiating a Lock implementation class.
  • Granular control: The synchronized keyword has a coarser granularity and can only achieve synchronous access to the entire method or code block, while the Lock interface can achieve more fine-grained synchronization control, such as synchronous access to different variables.
  • Reentrancy: The synchronized keyword is reentrant, that is, a thread can repeatedly acquire an already acquired lock, and the Lock interface can also implement reentrant locks, but the lock() and unlock() methods need to be explicitly called.
  • Condition variables: The Lock interface supports the function of condition variables, that is, the thread can wait for a certain condition to be met before continuing execution, but the synchronized keyword does not support condition variables.

84.What is deadlock? How to avoid deadlock?

Deadlock refers to a state in which multiple threads are waiting for each other to release the locks they hold, causing all threads to be unable to continue execution. Deadlock is a serious concurrency problem that reduces program performance and reliability.

Methods to avoid deadlock include the following aspects:

  • Avoid nested locks: Try to avoid acquiring another lock inside a lock, which can easily lead to deadlock.
  • Unify the locking order: If multiple locks must be used, the locking order should be unified. For example, acquire lock A first and then acquire lock B. All threads acquire locks in the same order to avoid deadlock.
  • Use tryLock() to avoid deadlock: When using the Lock interface, you can use the tryLock() method to acquire the lock. If the lock acquisition fails, it returns false, which can avoid the occurrence of deadlock.
  • Set a timeout: You can set a timeout when acquiring a lock to avoid deadlocks caused by threads waiting for the lock.
  • Use a thread pool: Using a thread pool can avoid deadlocks during thread creation and destruction.

85.What is a thread pool? Why do you need to use a thread pool?

The thread pool is a mechanism for managing threads. It can pre-create a certain number of threads when the program starts. When a task needs to be executed, an idle thread is obtained from the thread pool to execute the task. After the execution is completed, the thread is returned to the thread pool. , for next time use.

The benefits of using a thread pool include the following:

  • Reduce the consumption of system resources: The thread pool can control the number of threads and avoid the resource consumption caused by the creation and destruction of too many threads.
  • Improve program response speed: The thread pool can improve the response speed of tasks, because there are already a certain number of threads in the thread pool, which can respond to task requests immediately without waiting for the creation and initialization process of new threads.
  • Improve the stability of the system: The thread pool can avoid concurrency problems that occur during the creation and destruction of threads and improve the stability of the system.
  • Improve code readability and maintainability: Using a thread pool can encapsulate thread management logic together, improving code readability and maintainability.

86.What are the parameters of the thread pool? How to set the thread pool size?

The thread pool has the following parameters:

  • corePoolSize: The number of core threads, that is, the minimum number of threads maintained in the thread pool.

  • maximumPoolSize: The maximum number of threads, that is, the maximum number of threads that can be created in the thread pool.

  • keepAliveTime: The idle time of the thread. When the idle time of the thread exceeds this time, the excess threads will be destroyed until there are only corePoolSize threads left in the thread pool.

  • workQueue: Work queue, a queue used to store tasks.

  • threadFactory: Thread factory, used to create new threads.

  • handler: Rejection strategy, how to reject new tasks when the number of threads in the thread pool has reached the maximum number and the queue is full.

The size of the thread pool can be set based on the following factors:

  • Number of CPUs: The size of the thread pool should be set according to the number of CPUs. Generally, the size of the thread pool should be equal to the number of CPUs, so that CPU resources can be maximized.
  • Type of task: If the task is a CPU-intensive task, the size of the thread pool should be smaller than the number of CPUs, so as to avoid too many threads seizing CPU resources; if the task is an I/O-intensive task, then The size of the thread pool can be larger than the number of CPUs, because during the execution of tasks, threads will be in a state of waiting for I/O, and CPU resources are not fully utilized at this time.
  • Number of tasks: If the number of tasks is relatively small, the size of the thread pool can also be set relatively small; if the number of tasks is relatively large, then the size of the thread pool should be set relatively large.

87. How are tasks in the thread pool executed?

Tasks in the thread pool are executed through work queues. When a task reaches the thread pool, it will first determine whether the number of core threads is full. If it is not full, a new thread will be created to execute the task; if it is full, the task will be added to the work queue and wait for execution when the core thread is idle. Task.

When the work queue is also full, new threads will continue to be created to perform tasks until the maximum number of threads in the thread pool is reached. At this time, if there are new tasks arriving, the rejection policy will be executed.

88.What are the rejection strategies of the thread pool? How to customize denial policy?

Thread pool rejection policies include the following:

  • AbortPolicy: Throw an exception directly to prevent the system from running normally.
  • CallerRunsPolicy: Only use the caller's thread to perform tasks.
  • DiscardOldestPolicy: Discard the oldest task in the queue and try to submit the current task again.
  • DiscardPolicy: Discard the current task.

The rejection policy can be customized by implementing the RejectedExecutionHandler interface, for example:

public class MyRejectedExecutionHandler implements RejectedExecutionHandler {
    
    
    @Override
    public void rejectedExecution(Runnable r, ThreadPoolExecutor executor) {
    
    
        // 自定义拒绝策略的实现逻辑
    }
}

Then when creating the thread pool, use the setRejectedExecutionHandler() method to set a custom rejection policy, for example:

ThreadPoolExecutor executor = new ThreadPoolExecutor(5, 10, 60, TimeUnit.SECONDS, new ArrayBlockingQueue<>(100), new MyThreadFactory(), new MyRejectedExecutionHandler());

89. How is the order of task execution in the thread pool guaranteed?

The order of task execution in the thread pool is related to the queue in the thread pool. Generally speaking, the queue in the thread pool is divided into two types: bounded queue and unbounded queue.

  • A bounded queue refers to a queue with a fixed size. When the queue is full, new tasks will not be able to join the queue. In this case, the execution order of the thread pool depends on the thread pool's rejection policy. For example, if the AbortPolicy policy is adopted, new tasks will be discarded directly, causing the task execution order to be disordered.
  • An unbounded queue refers to a queue with no limit on size. When the queue is full, new tasks will wait until there is a free position in the queue. In this case, the execution order of the thread pool depends on how the queue is implemented. For example, if a PriorityBlockingQueue priority queue is used, the thread pool will prioritize tasks with higher priority in the queue.

90.What is CompletableFuture?

CompletableFuture is a new asynchronous programming framework in Java 8. It can easily implement asynchronous execution and callback functions, and provides a set of methods for operating asynchronous results, including chain calls, combined operations, and exception handling. wait.
CompletableFuture is a special Future that can not only obtain the results of asynchronous tasks, but also register a callback function and automatically execute the callback function when the task is completed, thereby realizing asynchronous programming. CompletableFuture also supports chained calls, that is, after one task is completed, you can continue to execute the next task, thereby realizing the concatenation of multiple asynchronous tasks.

91.What is the difference between CompletableFuture and Future?

Both CompletableFuture and Future can be used to execute tasks asynchronously and obtain results, but there are several differences between them:

  • The methods of asynchronous programming are different: Future's method is to block and wait for the asynchronous task to complete and obtain the result, while CompletableFuture's method is to register a callback function and automatically execute the callback function when the asynchronous task is completed.
  • Asynchronous results are handled differently: Future can only obtain the results of asynchronous tasks, while CompletableFuture provides a set of methods for operating asynchronous results, including chain calls, combined operations, exception handling, etc.
  • Different levels of feature richness: CompletableFuture provides richer asynchronous programming features than Future, such as supporting chain calls, combined operations, exception handling, etc.

92.How to create CompletableFuture?

CompletableFuture can be created in several ways:

Use the CompletableFuture.supplyAsync() method to create an asynchronous task with a return value:

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "hello");

Use the CompletableFuture.runAsync() method to create an asynchronous task with no return value:

CompletableFuture<Void> future = CompletableFuture.runAsync(() -> {
    
    
    // do something
});

Use the CompletableFuture.completedFuture() method to create a completed CompletableFuture:

CompletableFuture<String> future = CompletableFuture.completedFuture("hello");

93.How to add a callback function to CompletableFuture?

You can add callback functions to CompletableFuture through methods such as thenApply(), thenAccept(), thenRun() and thenCompose().

Among them, the thenApply() method is used to convert the results of asynchronous tasks and return a new CompletableFuture object, for example:

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "hello");
CompletableFuture<String> future2 = future1.thenApply(s -> s + " world");

In the above code, future1 is an asynchronous task with a return value. It returns the string "hello", which is then converted to "hello world" using the thenApply() method, returning a new CompletableFuture object future2.

The thenAccept() method is used to consume the results of asynchronous tasks and does not return any results, for example:

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "hello");
future.thenAccept(s -> System.out.println(s));

In the above code, future is an asynchronous task with a return value. It returns the string "hello", and then uses the thenAccept() method to consume it and output "hello".

The thenRun() method is used to execute a Runnable after the asynchronous task is completed. It does not accept any parameters and return values, for example:

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> "hello");
future.thenRun(() -> System.out.println("world"));

In the above code, the future is an asynchronous task with a return value, which returns the string "hello" and then uses the thenRun() method to output "world" when it completes.

The thenCompose() method is used to execute two asynchronous tasks in series, for example:

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "hello");
CompletableFuture<String> future2 = future1.thenCompose(s -> CompletableFuture.supplyAsync(() -> s + " world"));

In the above code, future1 is an asynchronous task with a return value. It returns the string "hello", and then uses the thenCompose() method to concatenate it with another asynchronous task to return a new CompletableFuture object future2, whose The result is "hello world".

94.How to combine multiple CompletableFutures?

Multiple CompletableFutures can be combined using methods such as thenCombine(), thenAcceptBoth(), runAfterBoth() and applyToEither().
Among them, the thenCombine() method is used to combine the results of two asynchronous tasks and return a new CompletableFuture object, for example:

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "hello");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "world");
CompletableFuture<String> future3 = future1.thenCombine(future2, (s1, s2) -> s1 + " " + s2);

In the above code, future1 and future2 are both asynchronous tasks with return values, returning the strings "hello" and "world" respectively, and then use the thenCombine() method to combine their results into "hello world" and return a new The CompletableFuture object future3.

The thenAcceptBoth() method and the runAfterBoth() method are used to execute a Runnable after both asynchronous tasks are completed. The thenAcceptBoth() method can consume the results of the two asynchronous tasks, for example:

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> "hello");
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> "world");
future1.thenAcceptBoth(future2, (s1, s2) -> System.out.println(s1 + " " + s2));

In the above code, future1 and future2 are both asynchronous tasks with return values, returning the strings "hello" and "world" respectively, and then using the thenAcceptBoth() method to consume their results and output "hello world".

The applyToEither() method is used to use the result of the first completed task among the two asynchronous tasks as the input of the conversion function and return a new CompletableFuture object, for example:

CompletableFuture<String> future1 = CompletableFuture.supplyAsync(() -> {
    
    
try {
    
    
Thread.sleep(1000);
} catch (InterruptedException e) {
    
    
e.printStackTrace();
}
return "hello";
});
CompletableFuture<String> future2 = CompletableFuture.supplyAsync(() -> {
    
    
try {
    
    
Thread.sleep(2000);
} catch (InterruptedException e) {
    
    
e.printStackTrace();
}
return "world";
});
CompletableFuture<String> future3 = future1.applyToEither(future2, s -> s + "!");

In the above code, future1 and future2 are both asynchronous tasks with return values, but their execution times are different. The execution time of future1 is 1 second, and the execution time of future2 is 2 seconds. Then use the applyToEither() method to apply the earliest The result of the completed task is used as input to the conversion function, which returns a new CompletableFuture object future3 whose result is "hello!".

95.How to handle exceptions in CompletableFuture?

Exceptions in a CompletableFuture can be handled using the exceptionally() method or the handle() method.

Among them, the exceptionally() method is used to handle exceptions in asynchronous tasks, for example:

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    
    
throw new RuntimeException("something went wrong");
});
future.exceptionally(ex -> "error: " + ex.getMessage());

In the above code, future is an asynchronous task with a return value, but it will throw a RuntimeException exception, and then use the exceptionally() method to handle the exception and return a new CompletableFuture object. The result is "error: something went wrong".

The handle() method is used to handle the results and exceptions of asynchronous tasks, such as:

CompletableFuture<String> future = CompletableFuture.supplyAsync(() -> {
    
    
throw new RuntimeException("something went wrong");
});
future.handle((result, ex) -> {
    
    
if (ex != null) {
    
    
return "error: " + ex.getMessage();
} else {
    
    
return result.toUpperCase();
}
});

In the above code, future is an asynchronous task with a return value, but it will throw a RuntimeException exception, and then use the handle() method to handle the exception and the result. If the asynchronous task is executed successfully, the result will be converted to uppercase, Otherwise, an error message is returned with the result "error: something went wrong".

五、Spring Cloud

96.What is Spring Cloud?

Spring Cloud is a framework for building distributed systems. It is developed based on Spring Boot and provides a series of tools and components for quickly building common patterns of distributed systems, such as service discovery, configuration center, load balancing, and circuit breaking. Servers, gateways, etc.

97.What is the relationship between Spring Cloud and Spring Boot?

Spring Cloud is based on Spring Boot. It provides Spring Boot's automatic configuration and convention-over-configuration features, allowing us to easily build distributed systems.

98. Please briefly introduce the components of Spring Cloud and their functions.

Spring Cloud contains many components. Here are some common components and their functions:

Eureka: service registration and discovery

Ribbon: load balancing

Hystrix: circuit breaker

Feign: Declarative service invocation

Zuul: gateway

Config: distributed configuration center

Bus: message bus

99.What is service registration and discovery? How is Eureka implemented?

Service registration and discovery means that the service registers its own information to the registration center when it starts. When other services need to call the service, they obtain the service information from the registration center and call it. Eureka is a service registration and discovery component that implements service registration and discovery through a heartbeat mechanism and client cache. Each service can register itself with the Eureka registration center when it starts, and periodically sends heartbeat packets to maintain the registration status. When a service needs to be called, the client obtains the address information of the service from the Eureka server and then calls it.

100.What is load balancing? How is Ribbon implemented?

Load balancing refers to allocating requests to multiple servers to balance the load and improve system availability and performance. Ribbon is a load balancing component that forwards requests to the target service node by obtaining a service list from the Eureka registration center and selecting the target service node according to certain rules. Ribbon provides some load balancing algorithms by default, such as polling, random, weighted random, etc.

101.What is a circuit breaker? How is Hystrix implemented?

A circuit breaker is a protection mechanism that quickly returns to a default value when a service call fails to avoid cascading failures caused by service failures. Hystrix is ​​a circuit breaker component that implements circuit breaker protection by inserting a circuit breaker between the client and server. When the service call failure reaches a certain threshold, Hystrix will short-circuit the service call and return a default value or an alternative.

6. MySQL

102.What is a database transaction? Please describe its ACID properties.

Answer: A database transaction refers to a logical unit of work consisting of a set of database operation sequences. Either all are executed successfully or all are rolled back to ensure data integrity and consistency. ACID refers to 4 characteristics that transactions must meet:

Atomicity: All operations in a transaction must succeed or fail, and partial success and partial failure are not allowed.

Consistency: The execution of a transaction must transform the database from one consistency state to another, that is, the integrity constraints of the database are not destroyed before and after the transaction is executed.
Isolation: Multiple transactions are independent of each other and invisible to each other. The data seen by each transaction is its own independent version and will not be interfered by other transactions.
Durability: Once a transaction is submitted successfully, its changes to the data in the database are permanent. Even if the system crashes, the data will not be lost.

103.What is an index? Why use indexes?

Answer: An index is a data structure used to improve the query speed of the database. It can quickly find the value of a specified column in a table. Using indexes can improve query speed, sorting speed and grouping speed, reduce the number of disk I/O operations, save query time, and improve database performance.

104.What are primary keys, unique indexes and ordinary indexes? What's the difference between them?

Answer: A primary key is a special unique index used to uniquely identify a record. The primary key can be a single column or a combination of multiple columns. Its value cannot be repeated and cannot be NULL.

A unique index is a restriction that is used to ensure that the value of a certain column or columns is unique. It allows NULL values, but there can only be one NULL value.

Ordinary index, also called non-unique index, is the most basic index type. It has no restrictions and allows duplicate values ​​and NULL values.

The main differences between them are:

The primary key must be unique and cannot be NULL. A unique index can only have one NULL value, while a normal index allows duplicate values ​​and NULL values.
The primary key can be a single column or a combination of multiple columns. Both the unique index and the ordinary index can be a single column or a combination of multiple columns.
The primary key is a special unique index that can be used to speed up queries, and unique indexes and ordinary indexes can also be accelerated

105.What are the classifications of databases?

Databases can be divided into relational databases and non-relational databases. Relational databases such as MySQL, Oracle, SQL Server, etc., and non-relational databases such as MongoDB, Redis, etc.

Summarize

In this article, I have summarized over 50,000 words of Java interview questions and answers. First, I provide some basic Java knowledge interview questions, including object-oriented programming, Java collection framework, multi-threaded programming, exception handling, and IO streams. Next, I listed some frequently asked questions about Java web development, such as Servlets, JSP, Spring, and Spring MVC. I then provide some frequently asked questions about databases and SQL, including basic concepts of MySQL, the query language, and the data model. Finally, I cover some interview questions about Spring Boot and Spring Cloud, including automatic configuration, dependency injection, and microservice architecture.

During the interview process, the interviewer may ask other questions, so we should remain sensitive and curious about new technologies and concepts. When answering questions, we should express our opinions as clearly and concisely as possible, give examples, and use actual project experience as examples. At the same time, we should pay attention to our attitude and language, and try to remain polite and confident.

Guess you like

Origin blog.csdn.net/xiangyuWA/article/details/129647288