【Java】Interview frequently asked knowledge points (Java basics-2)

java basics

state of multithreading

new state

When using the new operator to create a thread, such as new Thread(r), the thread has not yet started running, and the thread is in the newly created state. When a thread is in the nascent state, the program has not yet started running the code in the thread

ready state

A newly created thread does not automatically start running. To execute a thread, the thread's start() method must be called. When the thread object calls the start() method, the thread is started. The start() method creates the system resources for the thread to run, and schedules the thread to run the run() method. When the start() method returns, the thread is in the ready state.

The thread in the ready state does not necessarily run the run() method immediately. The thread must also compete with other threads for CPU time, and the thread can only be run if it obtains CPU time. Because in a single-CPU computer system, it is impossible to run multiple threads at the same time, and only one thread is running at a time. So there may be multiple threads in the ready state at this time. Multiple threads in the ready state are scheduled by the thread scheduler ( thread scheduler ) of the Java runtime system .

Operating status

When the thread obtains CPU time, it enters the running state and actually starts to execute the run() method.

blocked state

During the running of the thread, it may enter the blocked state due to various reasons:

1> The thread enters the sleep state by calling the sleep method;

2> The thread calls an operation that is blocked on I/O, that is, the operation will not return to its caller until the input and output operation is completed;

3> The thread tries to get a lock, which is being held by other threads;

4> The thread is waiting for a trigger condition;

state of death

There are two reasons for thread death:
  1) The run method exits normally and dies naturally,
   2) An uncaught exception terminates the run method and causes the thread to die suddenly.
  In order to determine whether the thread is currently alive (that is, either runnable or blocked), the isAlive method needs to be used. This method returns true if it is runnable or blocked; it returns false if the thread is still new and not runnable, or if the thread died.

What does the Java object header have 

How to make multiple threads execute sequentially

 public static void main(String[] args) throws Exception {
        thread1.start();
        thread1.join();

        thread2.start();
        thread2.join();

        thread3.start();
        thread3.join();

        thread4.start();
        thread4.join();

        thread5.start();
        thread5.join();
    }

Synchronized underlying principle, monitor operation process

Synchronized methods are locked implicitly by the ACC_SYNCHRONIZED keyword. When the method to be executed by the thread is marked with ACC_SYNCHRONIZED, it needs to obtain the lock before executing the method.

The synchronization code block performs locking through monitorenter and monitorexit. When the thread executes to monitorenter, the lock must be acquired before the subsequent methods can be executed. When the thread executes to monitorexit, the lock must be released. Each object maintains a counter of the number of times it is locked. When the counter is not 0, only the thread that acquires the lock can acquire the lock again

Synchronized lock upgrade process,

First of all, there are 4 states of the lock, from low to high: no lock --> biased lock --> light lock --> heavy lock. Locks can be upgraded but not downgraded

Biased lock: In most cases, not only does the lock not have multi-threaded competition, but it is always acquired by the same thread multiple times. In order to make the thread acquire the lock at a lower cost, a biased lock is introduced. When a thread accesses the synchronization code block and obtains the lock, it will record the thread ID storing the biased lock in the object header and the lock frame. After entering the synchronization code block, the thread first judges whether the MarkWord of the object header stores the bias pointing to the thread Lock, if it exists, get the lock directly

Lightweight lock: When other threads try to compete for a biased lock, the lock is upgraded to a lightweight lock. Before the thread executes the synchronization block, the JVM will first create a space for storing the lock record in the lock frame of the current thread, and replace the MarkWord of the object header with a pointer to the lock record. If successful, the current thread acquires the lock. If it fails, other threads are identified as competing for the lock, and the current thread tries to use spin to acquire the lock.

Heavyweight lock: When the lock is waiting in place, it will consume CPU resources. Therefore, the spin must have certain conditional control, otherwise, if a thread executes the synchronization code block for a long time, the thread waiting for the lock will continue to loop and consume CPU resources instead. By default, the number of lock spins is 10 times, and you can use the -XX:PreBlockSpin parameter to set the number of times the spin lock waits. If the lock has not been acquired after 10 times, it will be upgraded to a heavyweight lock

The difference between Synchronized and lock

Difference 1: Synchronized is a keyword of Java, and Lock is an interface under the java.util.concurrent.Locks package;

Difference 2: After Synchronized is used, the lock will be released automatically, while Lock needs to be locked and released manually. (in finally block (unlock))

Difference 3: Lock provides more implementation methods, and can respond to interrupts and timing, while the synchronized keyword cannot respond to interrupts;

eg:

Lock() ; //acquire lock

tryLock(); //Get the lock

tryLock(long time, TimeUnit unit); //After waiting for a certain time unit, try to acquire the lock;

lockInterruptibly(); //Acquire locks and respond to interrupts;

Response to interruption:

A and B threads want to acquire the lock at the same time. After A acquires the lock, B will wait. At this time, the thread B waiting for the lock will be interrupted by the Tread.interrupt() method, and then perform other things. The synchronized lock cannot be interrupted by the Tread.interrupt() method;

Difference 4: The synchronized keyword is an unfair lock, that is, the order of the threads waiting for the lock cannot be guaranteed, and the subclass of Lock, ReentrantLock, is an unfair lock by default, but a fair lock can be instantiated through a boolean parameter construction method;

Difference 5: synchronized cannot judge whether the lock has been acquired, but Lock can judge whether the lock has been acquired through the tryLock() method;

Difference 6: Lock can improve the efficiency of multiple thread read operations by defining read-write locks separately.

Difference 7: The underlying implementations of the two are different: synchronized is synchronous blocking, using a pessimistic concurrency strategy; Lock is synchronous non-blocking, using an optimistic concurrency strategy (the bottom layer is implemented based on the volatile keyword and the CAS algorithm)

CAS:

CAS, or Compare And Swap, means: compare and replace.

The CAS algorithm needs 3 operands: the memory address V, the old expected value A, and the target value B to be updated.

When the CAS instruction is executed, if and only if the value of the memory address V is equal to the expected value A, modify the value of the memory address V to B, otherwise do nothing. The entire compare and replace operation is an atomic operation.

CAS is an optimistic locking technology. When multiple threads try to use CAS to update the same variable at the same time, only one of the threads can update the value of the variable, while the other threads fail. The failed thread will not be suspended, but will be notified You lose this competition and can try again.

The usual way to use the CAS algorithm for synchronization is to read the value A from the address V, perform multi-step calculations to obtain a new value B, and then use the CAS algorithm to change the value of V from A to B. If the value at V has not changed at the same time, the CAS operation is successful.

The usual way to use the CAS algorithm for synchronization is to read the value A from the address V, perform multi-step calculations to obtain a new value B, and then use the CAS algorithm to change the value of V from A to B. If the value at V has not changed at the same time, the CAS operation is successful.

Volatile keyword

Volatile is a lightweight synchronization mechanism used in JMM (Java Memory Model) to ensure visibility and order.

It has two main functions. One is to ensure the visibility of the modified shared variable, that is, when multiple threads read and write, it can be perceived by other threads. It will force its own new value to be flushed back to the main memory; another important function is to prevent instruction reordering. In the double-check singleton we are familiar with, the instance must be modified with volatile. The reason is that there are generally three steps when creating a new singleton:

  1. allocate a block of memory
  2. Initialize the singleton object in memory
  3. Return this memory address and assign it to instance

But after optimization by the compiler, the order of 2 and 3 may be reversed, that is to say, the instance you may get may not have been initialized, and a null pointer exception may occur when accessing the member variable of the instance, and volatile can prevent this situation happened.

Briefly describe Lock and ReentrantLock

Lock is the top-level interface of java concurrent package.

ReentrantLock is the most common implementation of Lock, reentrant as synchronized. ReentrantLock is unfair by default, and a fair lock can be specified through the constructor. Once fair locks are used, performance will degrade.

How to ensure security when operating shared resources under multi-threading

Generally, locks are used to lock the smallest modules that can guarantee consistency.

A transfers money to B, how to ensure consistency under multi-threading?

The ThrealLocal class is used to achieve it. ThrealLocal is a map collection, which stores map(thread, T): the key identifies the current thread, and T identifies the generic value. Function: It can uniquely identify a thread, and different threads can have different identifications. This can ensure that during the transfer process, transaction operations can only be performed in the same thread. Ensure that the operations of transactions are isolated between different threads

try {

//Get the connection pool object, just like in the threadlical object.

connection = getDataResource().getConnection();

/ Put the connection into threadlocal /

threadLocal.set(connection);

} catch (SQLException e) {

e.printStackTrace();

}

threadLocal

Concurrency issues are prone to occur when multiple threads access the same shared variable, especially when multiple threads write to a variable, in order to ensure thread safety, generally users need to take additional synchronization measures when accessing shared variables to ensure thread safety. ThreadLocal is a way to ensure that in addition to the synchronization method of locking, a method to avoid thread insecurity in multi-threaded access. When we create a variable, if each thread accesses it, the access is The thread's own variables so that there will be no thread insecurity.

ThreadLocal is provided by the JDK package, which provides thread local variables. If you create a ThreadLocal variable, each thread that accesses this variable will have a copy of this variable. In actual multi-threaded operations, it operates its own local memory Variables in , thus avoiding thread safety issues

Implementation principle of threadLocal

set

Every time we set the value in ThreadLocal, it is stored in the threadLocals attribute of the current thread object, and the type of threadLocals is ThreadLocalMap. ThreadLocalMap can be understood as a customized HashMap implemented by the ThreadLocal class.

get

Same as the set method, first obtain the ThreadLocalMap object according to the current thread, and then get the value in the map.

AQS

Brief description:

AQS is actually a framework that can implement locks for us

The key to the internal implementation is: first-in first-out queue, state state

Defines the inner class ConditionObject

It has two thread modes exclusive mode and shared mode.

The relevant locks in the LOCK package (commonly used are ReentrantLock and ReadWriteLock) are all built based on AQS. Generally, we call AQS a synchronizer.

AQS is a multi-threaded synchronizer and a basic framework for building locks. Many components in the JUC package rely on it as the underlying implementation, such as CountDownLatch, Semaphora and other components. AQS provides two lock mechanisms: shared lock (read lock) and exclusive lock (write lock). A shared lock means that when multiple threads compete for the same shared resource, multiple threads can obtain it at the same time, while an exclusive lock can only have one thread obtain a shared resource at a time. AQS realizes mutual exclusion synchronization by setting an Int-type mutex variable state modified by volatile. When state=0, the lock of the table name can be acquired, and when state>=1, it indicates that the lock has been acquired. When the current lock is idle, multiple threads use the CAS method to modify the State value at the same time (guaranteeing atomicity and visibility), and finally only one thread successfully modifies and acquires the lock. After other threads fail, they will execute the park method of the unsafe class to block. The blocking method here creates a two-way queue to sequentially store lock competing threads, and first in first out to acquire the lock (fair lock method). The unfair lock method is that no matter whether there is a blocked thread in the doubly linked list queue, it will not enter the queue but directly try to modify the mutex variable to obtain the lock.

wait/sleep difference

1. from a different class

wait =>object

sleep =>thread

2. About the release of the lock

wait will release the lock

sleep will not release

3. The scope of application is different

wait: must be in a synchronous code block

sleep: can be anywhere

4. Do you need to catch exceptions

wait does not need to catch exceptions

sleep needs to catch exceptions

The difference between notify() and notifyAll()

  • notify()

    It is used to wake up a thread that is waiting for the corresponding object lock, so that it enters the ready queue, so as to compete for the lock after the current thread releases the lock, and then get the execution of the CPU.

  • notifyAll()

    It is used to wake up all threads that are waiting for the corresponding object lock, so that they enter the ready queue, so that they can compete for the lock after the current thread releases the lock, and then get the execution of the CPU.

The communication method between Java multithreading

There are three main ways of thread communication in Java:

  1. wait()、notify()、notifyAll()

    If synchronized is used between threads to ensure thread safety, wait(), notify(), and notifyAll() can be used to realize thread communication. These three methods are not methods declared in the Thread class, but methods declared in the Object class. The reason is that each object has a lock, so let the current thread wait for the lock of an object, of course, it should be operated through this object. And because the current thread may wait for the locks of multiple threads, it is very complicated to operate through threads. In addition, these three methods are all local methods and are modified by final and cannot be overridden.

    The wait() method allows the current thread to release the object lock and enter the blocked state. The notify() method is used to wake up a thread that is waiting for the corresponding object lock, so that it enters the ready queue, so that after the current thread releases the lock, it can compete for the lock, and then get the execution of the CPU. notifyAll() is used to wake up all threads that are waiting for the corresponding object lock, so that they enter the ready queue, so that they can compete for the lock after the current thread releases the lock, and then get the execution of the CPU.

    Each lock object has two queues, one is the ready queue and the other is the blocking queue. The ready queue stores threads that are ready (to compete for locks), and the blocking queue stores blocked threads. When a blocked thread is woken up, it will enter the ready queue and wait for the CPU to schedule. Conversely, when a thread is waited, it will enter the blocking queue, waiting to be woken up.

  2. await()、signal()、signalAll()

    If Lock is used between threads to ensure thread safety, await(), signal(), signalAll() can be used to implement thread communication. These three methods are methods in the Condition interface, which appeared in Java 1.5, and it is used to replace the traditional wait+notify to realize the cooperation between threads, and its use depends on Lock. Compared with using wait+notify, using Condition's await+signal can achieve inter-thread collaboration more safely and efficiently.

    Condition depends on the Lock interface, and the basic code to generate a Condition is lock.newCondition(). It must be noted that the use of await()/signal()/signalAll() of Condition must be within the protection of the lock, that is, it must be used between lock.lock() and lock.unlock. In fact, await()/signal()/signalAll() has a natural correspondence with wait()/notify()/notifyAll(). That is: await() in Condition corresponds to wait() of Object, signal() in Condition corresponds to notify() of Object, and signalAll() in Condition corresponds to notifyAll() of Object.

  3. BlockingQueue

    Java 5 provides a BlockingQueue interface. Although BlockingQueue is also a sub-interface of Queue, its main purpose is not as a container, but as a tool for thread communication. BlockingQueue has a characteristic: when the producer thread tries to put elements into the BlockingQueue, if the queue is full, the thread is blocked; when the consumer thread tries to take out elements from the BlockingQueue, if the queue is empty, the thread Thread is blocked.

    The two threads of the program can control the communication of the threads by alternately putting elements into and taking out elements from the BlockingQueue. Threads need to communicate. The most classic scenario is the producer-consumer model, and BlockingQueue is the solution for this model.

Spring framework and SpringMVC framework

Inversion of Control (IOC)

IoC is the core content of the Spring framework. IoC is perfectly implemented in a variety of ways, including XML configuration and annotations. The new version of Spring can also implement IoC with zero configuration.

When the Spring container is initialized, it first reads the configuration file, creates and organizes objects according to the configuration file or metadata and stores them in the container, and then takes out the required objects from the Ioc container when the program is used.

This process is called inversion of control:

Control: Who controls the creation of objects. The objects of traditional applications are created by the program itself. After using Spring, the objects are created by Spring. The reverse: the program itself does not create objects, but becomes a passive receiving object. Dependency injection: is to use the set method to inject.

IOC is a programming idea, from active programming to passive reception

AOP (Aspect Oriented Programming)

The proxy mode is mainly used to extract and encapsulate public behaviors and logic that have nothing to do with business but affect multiple objects into a reusable module. This module is named "Aspect". Reduce the repeated code in the system, reduce the coupling degree between modules, and improve the maintainability of the system at the same time.

1. Spring creates an IOC container to first scan all classes modified by @Service and @Component in the package, and create objects for them, and place them in the Spring IOC container. 2. Find the aspect class After creating the object, Spring starts looking for the aspect class modified by @Aspect and obtains all the methods in the aspect class. 3. Find the part with expressions in the method of the aspect class Next, Spring finds all the methods decorated by legal expressions 4. Find the class with the corresponding method Then, Spring checks all the classes it scans, and uploads The method found in the first step is compared with all classes to find out the class with this (some) method (this class is the proxy class). 5. Create dynamic objects Finally, Spring creates dynamic objects of dynamic classes based on the proxy class and aspect class found in the previous step and puts them in the Spring IOC container.

type:

Pre-notification (Before): call the notification function before the target method is called; Post-notification (After): call the notification after the target method is completed, and do not care what the output of the method is at this time; return notification (After-returning) : The notification is called after the target method is successfully executed; After-throwing: The notification is called after the target method throws an exception; Around the notification (Around): The notification wraps the notified method, before the notified method is called and Execute custom behavior after calling.

What design pattern does spring use

1. Proxy mode: it is used more in AOP and remoting

2. Singleton mode: The bean defined in the spring configuration file defaults to the singleton mode

3. Template method mode: solve the problem of code duplication

The parent class defines the skeleton (implementation of common methods, which methods are called and the order), and some specific methods are implemented by subclasses (the parent class is an empty method, which is rewritten after subclass inheritance)

4. Front controller mode: spring provides DispatcherServlet to distribute requests

5. Dependency Injection Mode: The core concept throughout the BeanFactory and ApplicationContext interfaces

6. Factory mode: bean

7. Adapter mode: Implementation method: Adapter HandlerAdapter in springmvc

8. Decorator mode:

Implementation method: the class name contains Wrapper, or Decorator, which is the decorator mode

Essence: Dynamically add some additional responsibilities to an object, which is more flexible than generating subclasses

9. Observer pattern

Implementation method: The event-driven model of spring uses the observer mode, and the commonly used place is the implementation of listener

Specific implementation: The implementation of the event mechanism includes event sources, events, and event listeners:

ApplicationEvent abstract class [event]

ApplicationListener interface [event listener]

ApplicationContext interface [event source]

10. Strategy mode

Implementation method: the resource access Resource interface of the spring framework is an abstraction of specific resource access strategies, and it is also the interface implemented by all resource access classes

springmvc execution process

1. The user sends a request to the front controller DispatcherServlet.

2. DispatcherServlet receives a request to call HandlerMapping processor mapper.

3. The processor mapper finds the specific processor (can be searched according to the xml configuration and annotation), generates the processor object and the processor interceptor (if there is one), and returns it to the DispatcherServlet.

4. DispatcherServlet calls HandlerAdapter processor adapter.

5. The HandlerAdapter calls a specific processor (Controller, also called a back-end controller) after adaptation.

6. After the execution of the Controller is completed, it returns to the ModelAndView.

7. HandlerAdapter returns the controller execution result ModelAndView to DispatcherServlet.

8. DispatcherServlet passes ModelAndView to ViewReslover view parser.

9. ViewReslover returns a specific View after parsing.

10. DispatcherServlet renders the view according to the View (that is, fills the model data into the view).

11. DispatcherServlet responds to the user.

bean life cycle

Commonly used annotations in Spring

 

1、@Controller

The Bean corresponding to the presentation layer, that is, Action, incorporates the class marked with this annotation into the spring container for management

2、@RequestMapping

RequestMapping is an annotation used to process request address mapping, which can be used on classes or methods. It is used on a class to indicate that all methods in the class that respond to requests use this address as the parent path.

3. @Resource and @Autowired

Both @Resource and @Autowired are used for bean injection. In fact, @Resource is not a Spring annotation. Its package is javax.annotation.Resource, which needs to be imported, but Spring supports the injection of this annotation.

4、@ModelAttribute和 @SessionAttributes

It means: before calling all the methods of the Controller, execute this @ModelAttribute method first, which can be used in annotations and method parameters. You can apply this @ModelAttribute feature to BaseController. All Controllers inherit from BaseController and can be implemented in When calling the Controller, execute the @ModelAttribute method first. @SessionAttributes puts the value in the session scope and writes it on the class.

5、@PathVariable

It is used to map the template variables in the request URL to the parameters of the function processing method, that is, to take the variables in the uri template as parameters.

6、@requestParam

@requestParam is mainly used to obtain parameters in the SpringMVC background control layer, similar to request.getParameter("name"), which has three common parameters: defaultValue = "0", required = false, value = "isApp"; defaultValue means Set the default value, required boolean to set whether it is a parameter that must be passed in, and the value value indicates the type of parameter that is accepted.

7、@ResponseBody

Function: This annotation is used to convert the object returned by the Controller method into the specified format through the appropriate HttpMessageConverter, and then write it into the body data area of ​​the Response object.

When to use: Use when the returned data is not a page with html tags, but data in some other format (such as json, xml, etc.);

8、@Component

It is equivalent to a general annotation, which is used when you don't know which layer some classes belong to, but it is not recommended.

9、@Repository

It is used to annotate the dao layer and annotate on the daoImpl class.

10、@configuration

1. Indicate that the current class is a configuration class, which is the source of the method bean
2. Assign the beanDefinitioin attribute of AppConfig configured by @Configuration to the full type to ensure that the AppConfig type can be converted to the cglib type

3. Change the AppConfig configured by @Configuration from a normal type to a cglib proxy type, and then generate a cglib proxy object. Through the method interceptor of the proxy object, it can solve the problem of obtaining from the container when there is a dependency call between AppConfig internal method
  beans , avoiding the occurrence of multiple cases

 

Guess you like

Origin blog.csdn.net/weixin_46601559/article/details/130513232