First, talking about the interview

1. The interview is mainly divided into two parts: one is to test the engineers on the basic knowledge (including technical breadth, depth, enthusiasm for technology, etc.) degree of mastery, because the basic knowledge determines the upper limit of a technical personnel development; The other examined the engineering skills of the engineers, such as: what projects have they worked on? How did you solve your most difficult problem? What was your most fulfilling assignment? Engineering capability is a measure of what an engineer can bring to the company right now. Of course, there are other aspects of assessment: stress tolerance, cooperation ability.

2.Java is only a language, even Java engineers can not be limited to Java, to the object-oriented language itself, even from the whole computer system, from the engineering practice to see Java.

3. A lot of knowledge is not needed in the development of the average company. It is often joked that “interview builds the rocket, work turns the screw”, but this is usually the company’s standard for programmers — to produce quickly and complete the task. Therefore, engineers for the development of their own career can not be limited to the company’s requirements for their own, can not stay in the application level, to be able to master the basic knowledge, to read the source code, their own practice, learn to remember output, such as contributing code to the open source community, help beginners to guide.

In fact, behind the “interview makes the rocket, work turns the screw” is the general recognition of the importance of basic knowledge.

Second, concurrent programming often meet questions

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

There are two types of threads in Java: daemons and User threads.

Any Thread can be set to daemon and user threads using thread.setdaemon (bool on); True sets the thread to daemon or user. Thread.setdaemon () must be called before Thread.start(), otherwise the runtime will throw an exception.

The difference between the two:

The only difference is to determine when the VIRTUAL machine (JVM) has left. Daemons serve other threads. If all User threads have ended and there are no more threads to serve, the JVM shuts down.

Extension: Thread dumps printed information about threads. Threads containing the word daemon are daemons

2. Difference between thread and process

Process is the smallest unit of operating system allocation of resources, thread is the smallest unit of operating system scheduling.

A program has at least one process, and a process has at least one thread.

3. What is context switching in multithreading

Multiple threads share the CPUS on a set of computers, and when the number of threads is greater than the number of cpus allocated to the program, the CPU needs to be rotated so that each thread has a chance to execute. Switching data between different threads using the CPU is a context switch.

4. The difference between deadlock and live lock, deadlock and starvation?

Deadlock: A situation in which two or more processes (or threads) are waiting for each other to execute because they are competing for resources and cannot proceed without external forces.

The necessary conditions for a deadlock to occur:

Mutual exclusion conditions: Mutual exclusion is when a process monopolizes resources for a certain period of time.

Request and hold conditions: when a process is blocked by requesting resources, it holds on to acquired resources.

Non-dispossession condition: a process has acquired a resource and cannot take it away until it is used up.

Circular waiting condition: a circular waiting resource relationship is formed between several processes.

Live lock: a task or performer that is not blocked is repeatedly tried, failed, tried, failed because some condition is not met.

The difference between a live lock and a deadlock is that an entity in a live lock is in a state of constant change, called “alive”, while an entity in a deadlock is waiting; Live locks can unlock themselves, deadlocks cannot.

Hunger: A state in which one or more threads are unable to execute because they cannot get the resources they need for any reason.

5, synchronized Underlying Implementation Principles

Principle of synchronized (this) : Involves two commands: monitorenter, Monitorexit; Monitorenter and Monitorexit do not synchronize the synchronized methods. The constant pool of monitorenter and Monitorexit contains the ACC_SYNCHRONIZED identifier.

\

The JVM implements method synchronization based on this identifier: When a method is called, the calling instruction will check whether the ACC_SYNCHRONIZED access flag of the method is set. If so, the executing thread will acquire monitor first and execute the method body only after the method is successfully acquired. Monitor will be released after the method is executed. During method execution, the same Monitor object is no longer available to any other thread.

Note that this question may then be asked about Java object headers, bias locks, lightweight locks, heavyweight locks, and their interconversion.

6. What are thread groups and why are they not recommended in Java?

The ThreadGroup class allows threads to be grouped into a ThreadGroup, which can have thread objects, thread groups, and threads in a tree-like structure.

Some useful methods in ThreadGroup object are stop, resume, suspend and so on. These methods cause thread safety problems (mainly deadlocks) and have been officially abandoned. Therefore, the application value of ThreadGroup itself has been greatly reduced.

2. Threadgroups are not thread-safe, so the information acquired during use is not all timely and effective, which reduces their statistical use value.

7. What is Executors Framework? Why use the Executor framework?

The Executor framework is a framework for invoking, scheduling, executing, and controlling asynchronous tasks based on a set of execution policies.

New threads () are created for each task. Creating a Thread is time consuming and resource consuming.

Threads created by calling new threads () are poorly managed and can be created indefinitely. Competition between threads will lead to excessive use of system resources and system breakdown, and frequent alternation between threads will consume a lot of system resources.

Connecting threads started with new threads () is not scalable, such as scheduled execution, scheduled execution, scheduled execution, Thread interruption, etc.

The difference between Exector and Executors in Java?

Different methods of the Executors tool class created different thread pools according to our requirements to meet business requirements.

The Executor interface object can perform our threading tasks.

The ExecutorService interface extends and inherits the Executor interface, providing additional methods for obtaining the status of tasks executed and the return value of tasks.

Custom thread pools can be created using ThreadPoolExecutor.

9. What is atomic operation? What atomic classes are available in the Java Concurrency API?

An atomic operation means “an operation or series of operations that cannot be interrupted”.

The processor implements atomic operations between multiple processors based on cache locking or bus locking.

\

Atomic operations can be implemented in Java by locking and looping CAS. CAS operations — Compare & Set, or Compare & Swap — are now supported by almost all CPU instructions. Under the Java. Util. Concurrent. Atomic offers a wide range of atomic operations, such as atomic classes: AtomicBoolean, AtomicInteger, AtomicLong, AtomicReference, atom array: AtomicIntegerArray, AtomicLongArray, AtomicReferenceArray, atomic property update: AtomicLongFieldUpdater AtomicIntegerFieldUpdater, AtomicReferenceFieldUpdater

Java Concurrency API What is the Lock interface in? What are its advantages over synchronized?

The Lock interface provides a more extensible locking operation than synchronized methods and synchronized blocks.

They allow for more flexible structures that can have radically different properties, and can support conditional objects of multiple related classes.

It has the following advantages: it can make locks fairer, it can make threads respond to interrupts while waiting for locks, it can make threads try to acquire locks and immediately return or wait for a period of time when the locks cannot be acquired, and it can acquire and release locks in different ranges and in different sequences.

Lock is generally an extension of synchronized, Lock provides unconditional, pollable (tryLock method), timed (tryLock parameterized method), interruptibly (lockInterruptibly), and multi-conditional queued (newCondition method) Lock operations. In addition, Lock implementation classes basically support unfair Lock (default) and fair Lock, synchronized only supports unfair Lock, of course, in most cases, unfair Lock is an efficient choice.

What is a blocking queue? What is the implementation principle of blocking queues? How to implement the producer-consumer model using blocking queues?

A BlockingQueue is a queue that supports two additional operations.

The two additional operations are: when the queue is empty, the thread that fetched the element waits for the queue to become non-empty. When the queue is full, the thread that stores the element waits for the queue to become available.

Blocking queues are often used in producer and consumer scenarios, where the producer is the thread that adds elements to the queue and the consumer is the thread that takes elements from the queue. A blocking queue is a container in which producers hold elements, and consumers only take elements from the container.

JDK7 provides seven blocking queues. In the realization, Condition and Lock wait notification modes are mainly used.

12. What are Callable and Future?

The Callable interface is similar to Runnable, as the name suggests, but Runnable does not return a result and cannot throw an exception that returns a result. A Callable is more powerful. When executed by a thread, it can return a value that can be retrieved by the Future. The Future can get the return value of the asynchronously executed task.

Think of it as Runnable with a callback.

The Future interface represents asynchronous tasks that are Future results of tasks that have not yet been completed. So Callable is used to produce results and Future is used to get results.

13. What is FutureTask?

In Java concurrent programs, FutureTask represents an asynchronous operation that can be cancelled. It has methods to start and cancel operations, to check whether an operation is complete, and to retrieve the result of an operation. The result can only be retrieved when the operation is complete, and the GET method will block if the operation is not complete. A FutureTask object can wrap objects that call Callable and Runnable, and since FutureTask also calls the Runnable interface, it can be submitted to Executor for execution.

14. What is the implementation of concurrent containers?

What a synchronized container is: A container that can be understood simply as synchronized. If multiple threads call the synchronized container methods, they are executed serially. Such as Vector, Hashtable, and Collections. SynchronizedSet synchronizedList method such as returned by the container.

Concurrent containers use a completely different locking strategy from synchronous containers to provide higher concurrency and scalability. For example, in ConcurrentHashMap, a more fine-grained locking mechanism is used, which can be called segment-based locking. In this locking mechanism, any number of readers are allowed to access the map concurrently. In addition, the read thread and the write thread can concurrently access the map, while allowing a certain number of write threads to concurrently modify the map, so it can achieve higher throughput in a concurrent environment.

15, There are several ways to implement multithreaded synchronization and mutex. What are they?

Thread synchronization refers to a restriction relationship between threads. The execution of one thread depends on the message of another thread. When it does not receive the message of another thread, it should wait until the message arrives and is woken up.

Thread mutex refers to the exclusive access of individual threads to shared process system resources. When several threads are using a shared resource, only one thread is allowed to use it at any time, and other threads must wait until the hogger releases the resource. Thread mutex can be thought of as a special kind of thread synchronization.

Synchronization methods between threads can be broadly divided into two categories: user-mode and kernel-mode. As the name implies, kernel mode refers to the use of the system kernel object singleness to synchronize, the use of the need to switch between the kernel state and the user state, and user mode is not required to switch to the kernel state, only in the user state to complete the operation.

Methods in user mode include: atomic operations (such as a single global variable), critical sections. Kernel-mode methods include events, semaphores, and mutex.

What are the conditions of competition?

A race condition occurs when multiple processes attempt to perform some kind of processing on shared data, and the final outcome depends on the order in which the processes run.

17. Why do we call run() when we call start()? Why can’t we call run() directly?

When you call the start() method you will create a new thread and execute the code in the run() method.

But if you call the run() method directly, it doesn’t create a new thread or execute the code that calls the thread. It just executes the run method as if it were a normal method.

What is the difference between CycliBarriar and CountdownLatch in Java?

CyclicBarrier can be reused, but CountdownLatch cannot.

19. What are immutable objects and how does it help write concurrent applications?

Immutable Objects are Mutable Objects that cannot change their state (their data, or property values) once they are created.

Classes of Immutable objects are Immutable classes. The Java platform class library contains immutable classes such as String, primitive wrapper classes, BigInteger, and BigDecimal.

Immutable objects are inherently thread-safe. Their constants (fields) are created in the constructor. Since their state cannot be changed, these constants never change.

Immutable objects are always thread-safe.

An object is immutable only if it is;

Its state cannot be changed after creation;

All fields are final; And,

It was created correctly

20, notify () What’s the difference from notifyAll()?

When a thread enters a wait, it must wait for notify/ NotifyAll. Notifyall awakens all threads in wait state to re-enter the lock contention queue. Notifyall awakens only one thread.

If not, notifyAll is recommended to prevent Notigy from causing program exceptions due to signal loss.

21. What is a ReentrantLock? Talk about its implementation.

A thread can repeatedly enter any block of code synchronized with a lock it already owns. Synchronized and ReentrantLock are reentrant locks. In terms of implementation, when a thread obtains a lock, it decides that if the thread that obtains the lock is itself, it simply accumulates the counter. Every time the lock is released, it accumulates the counter until the calculator returns to zero, indicating that the thread has completely released the lock.

22. When a thread accesses a synchronized instance of an object, can other threads access other synchronized methods?

Other threads can enter if other methods are not synchronized.

So to open a thread-safe object, make sure that every method is thread-safe.

23, optimistic lock and pessimistic lock understanding and how to achieve, what is the way to achieve?

Pessimistic locking: Always assume the worst, every time you go to get the data you think someone else will change it, so every time you get the data you lock it, so that someone else tries to get the data it will block until it gets the lock. The implementation of the synchronized keyword in Java is pessimistic locking.

Optimistic lock: as the name implies, is very optimistic, every time to get the data, I think others will not modify, so I will not lock, but when updating, I will judge whether others have to update the data during this period, you can use the version number and other mechanisms. In Java, the J atomic variable class is implemented CAS using an implementation of optimistic locking.

Optimistic locking can be implemented as follows:

  • Use version identifiers to determine whether the data read is consistent with the data submitted. Modify the version id after submission, and discard and try again if it is inconsistent.
  • In Java, Compare and Swap is CAS. When multiple threads try to update the same variable using CAS, only one thread can update the value of the variable, and all the other threads fail. The thread that fails will not be suspended, but will be informed that it has lost the competition and can try again.

24. What is CAS operation and what are its disadvantages?

The basic idea of CAS is that if the value at this address is the same as the expected value, it assigns it a new value, otherwise it does nothing, but returns what the original value was. Each CAS operation contains three operators: A memory address V, A desired value A, and A new value B. The CAS operation assigns the value of the address to the new value B if the value stored at the address is equal to the desired value A, otherwise no operation is performed.

CAS faults:

ABA problem:

For example, thread one fetches A from location V, and another thread Two fetches A from location V, and two does something to change the data from location V to A. Then thread one performs the CAS operation and finds that there is still A in memory, and thread One succeeds. Although the CAS operation for thread one was successful, there may be a lurking problem. Since Java1.5, the JDK atomic package has provided a class AtomicStampedReference to address ABA issues.

Long cycle time and high overhead:

In the case of serious resource competition (serious thread conflict), CAS has a high probability of spin, which wastes more CPU resources and is less efficient than synchronized.

Atomic operations that can only be guaranteed for one shared variable:

When performing operations on a shared variable, we can loop CAS to ensure atomic operations, but when performing operations on multiple shared variables, the loop CAS cannot guarantee atomic operations, so we can use locks.

25, SynchronizedMap What’s the difference with ConcurrentHashMap?

SynchronizedMap locks the entire table at a time to ensure thread-safety, so only one thread can call the map at a time.

ConcurrentHashMap uses segmented locking to ensure performance in multiple threads.

26. What application scenarios can copy-on-write containers be used for?

The CopyOnWrite concurrent container is used in concurrent scenarios where most access is read and only occasionally written. Such as whitelisting, blacklisting, commodity access and update scenarios.

Revealed thought

Separate reading and writing, separate reading and writing

Final consistency

Use alternate space ideas to resolve concurrency conflicts

27, volatile What’s the use? Can you explain in one sentence how volatile is used?

Volatile ensures memory visibility and disallows instruction reordering.

Volatile is used for write multiread or unassociated multiwrite in a multithreaded environment.

28. Why is code reordered?

When executing a program, processors and compilers often reorder instructions to provide performance. However, reordering is not optional. It requires that the following two conditions be met:

In a single thread environment cannot change the results of the program running;

Data dependencies cannot be reordered

What is the difference between wait and sleep in Java?

The big difference is that while wait releases the lock, sleep holds it all the time. Wait is usually used for interthread interactions, and sleep is usually used to pause execution.

30. What happens when an exception occurs while a thread is running?

The thread will stop execution if the exception is not caught. Hread UncaughtExceptionHandler is used for uncaught exception handling and interrupted threads of an embedded interface. When an uncaught exception Thread will break off when the JVM can use Thread. GetUncaughtExceptionHandler () to query the Thread UncaughtExceptionHandler Thread and uncaught exception passed as a parameter to the handler The Exception() method.

31. Why don’t Wait, notify, and notifyAll belong to Thread?

JAVA provides locks at the object level rather than the thread level. Each object has a lock, which is acquired by the thread. It makes sense to call wait() on an object if the thread needs to wait for some lock. If the wait() method is defined in the Thread class, it is not obvious which lock the Thread is waiting on. Simply put, because wait, notify, and notifyAll are lock-level operations, we define them in the Object class because locks belong to objects.

32. What are ThreadLocal variables?

ThreadLocal is a special kind of variable in Java. A ThreadLocal for each thread means that each thread has its own independent variable, eliminating the contention condition completely.

33, Java What is the difference between the interrupted and isInterrupted methods?

The main difference between interrupted() and isInterrupted() is that the former clears the interrupted state while the latter does not. The interrupt mechanism for Java multithreading is implemented with an internal identifier. Calling thread.interrupt () to interrupt a Thread sets the interrupt identifier to true. The interrupted status is cleared when the interrupted Thread calls the static method thread.interrupted () to check the interrupted status. The non-static isInterrupted() method is used to query the interrupted status of other threads without changing the interrupt status flag.

34. Why are wait and notify called in synchronous blocks?

Mainly because the Java API forced to do so, if you don’t do this, your code will be thrown IllegalMonitorStateException anomalies.

35. Why should you check the wait condition in a loop?

Threads in the wait state may receive error alerts and pseudo-awakenings, and if the wait condition is not checked in the loop, the program will exit without meeting the end condition. Therefore, when a wait thread wakes up, its original wait state cannot be considered to be still valid; it may change between the time after the notify() call and the time before the wait thread wakes up. This is why using wait() in a loop works better

How do I check if a thread has a lock?

There is a method called holdsLock() in java.lang.Thread that returns true if and only if the current Thread has a lock on a specific object.

37. How do you get a thread stack in Java?

kill -3 [java pid]

It will not be output at the current terminal, it will be output to the code execution or specified. For example, kill -3 tomcat PID to output the stack to the log directory.

Jstack [java pid]

This is relatively simple and can be displayed on the current terminal or redirected to a specified file.

Or use Java provide quasi machine thread system management interface ManagementFactory. GetThreadMXBean ().

38, Java What is the difference between submit() and execute() methods in a thread pool?

Both methods can submit tasks to a thread pool, and the execute() method returns void, which is defined in the Executor interface.

The Submit () method, on the other hand, returns a Future object holding the results, defined in the ExecutorService interface, which extends the Executor interface

39. What do you understand about thread priorities?

Each thread has priority. Generally speaking, threads with higher priority have priority at run time, but this depends on the implementation of thread scheduling, which is OS dependent. We can define the priority of a thread, but this does not guarantee that a higher-priority thread will execute before a lower-priority thread. Thread priority is an int variable (1-10), with 1 representing the lowest priority and 10 representing the highest priority.

Java thread priority scheduling is delegated to the operating system, so it depends on the operating system priority. You do not need to set thread priority unless it is necessary.

40. How do you ensure that the thread on which the main() method is located is the last thread to terminate a Java program?

You can use the Join () method of the Thread class (or the CountDownLatch utility class) to ensure that all threads created by the program end before the main() method exits.

Why are Thread sleep() and yield () static?

The Sleep () and yield() methods of the Thread class will run on the Thread currently executing. So it doesn’t make sense to call these methods on other threads that are in the wait state. That’s why these methods are static. They work in the currently executing thread and prevent programmers from making the mistake of thinking they can be called in another non-running thread.

Now there are three threads: T1, T2, and T3. How do you ensure that T2 is executed after T1 and T3 after T2?

This can be done using the Join method.

43. You need to implement an efficient cache that allows multiple users to read, but only one user to write, in order to maintain its integrity. How would you implement it?

Volatile keywords, read-write locks, copy-on-write, and so on can be implemented.

Write code in Java to solve the producer-consumer problem.

This can be done with wait and notify, or Semaphore

45, Java How to stop a thread?

How to use shared variables

In this way, a shared variable is introduced because it can be used by multiple threads performing the same task as an interrupt signal to inform the interrupt thread of its execution.

Terminate a thread with the interrupt method

If a thread is blocked waiting for something to happen, how do you stop it? For example, when a Thread is blocked because it needs to wait for keyboard input, or thread.join () is called, or thread.sleep () is called, or serversocket.accept () is called in the network, Or a call to datagramsocket.receive () can block the thread, leaving it in an unrunnable state that, even if the main program sets the thread’s shared variable to true, cannot check for the loop flag and therefore cannot immediately interrupt. Use thread_interrupt () whenever possible, because while it does not interrupt a running Thread, it can cause a blocked Thread to throw an interrupt exception, causing the Thread to end its blocking state prematurely.

46, the JVM Which parameter is used to control the stack size of the thread

-Xss

Will the lock be released if a thread in the synchronized block throws an exception?

will

What is the double-checked implementation of the singleton pattern? Why isn’t it safe? How to create a thread-safe Singleton in Java?

The root cause of insecurity is that reordering causes uninitialized objects to be seen by other threads, resulting in errors. Examples of safe singleton patterns are: delayed placeholder, instances of the class new when declared, and enumerations

Write down 3 best practices for multithreading that you follow

Give your threads meaningful names. This makes it easy to find bugs or track them. OrderProcessor, QuoteProcessor, or TradeProcessor are better names than thread-1, thread-2, or thread-3. Give a Thread a name that relates to the task it’s trying to accomplish. All major frameworks, even the JDK, follow this best practice.

Avoid locking and narrowing the scope of synchronization. Locking is expensive and context switching is time and space consuming. Try minimizing synchronization and locking and narrowing the critical area. So I prefer synchronized blocks to synchronized methods, which give me absolute control over the lock.

First of all, CountDownLatch, Semaphore, CyclicBarrier and Sanodomain simplify encoding, while WAIT and notify are difficult to control complex control flows. Second, these classes are written and maintained by the best companies and will continue to be refined and refined in subsequent JDKS. With these higher-level synchronization tools, your programs can be optimized without much effort.

Another best practice that is easy to follow and hugely beneficial is to use more concurrent collections and less synchronous collections. Concurrent collections are more scalable than synchronous collections, so they work better when programming concurrently.

Like the golden rule of concurrent programming, programming as lock-free as possible… .

Outline the parameters for creating a thread pool. How to configure the parameters for a thread pool?

See chapter 1 of concurrent Programming topics

51. Outline fair and unfair locking and how it is implemented internally in the JDK.

A fair lock means that all threads trying to acquire the lock acquire the lock in the sequence of acquiring the lock, while a non-fair lock means that when the current lock state is not occupied, the current thread can directly occupy it without waiting. In terms of implementation, unfair lock logic is basically the same as fair lock, the only difference is that the current thread does not need to determine whether there is a waiting thread in the synchronization queue.

Unfair lock performance is higher than fair lock performance. First, there is a significant delay between resuming a suspended thread and actually running it. Moreover, the unfair lock can make full use of the CPU time slice and reduce the idle state time of the CPU as far as possible.

The usage scenarios depend on their attributes one by one. For example, if the thread takes much longer to process than the thread waits, then using unfair locks is not efficient, but using fair locks ensures that no thread will starve to death.

Please outline AQS

AQS is a basic framework for building locks and other synchronization components, such as ReentrantLock, ReentrantReadWriteLock, and CountDownLatch. It uses an int member variable to indicate synchronization status, and queues the resource acquisition threads through a built-in FIFO queue. It is a variant implementation of CLH queue locks. It can implement two synchronization modes: exclusive and shared.

The primary use of AQS is inheritance. Subclasses manage synchronization state by inheritingAQS and implementing its abstract methods. The synchronizer design is based on the template method pattern, so if we want to implement our own synchronization utility class, we need to override several of these rewritable methods, such as tryAcquire, tryReleaseShared, and so on.

The purpose of this design is that synchronous components (such as locks) are consumer-oriented. It defines the interface for the user to interact with the synchronous components (such as allowing two threads to access them in parallel) and hides implementation details. Synchronizer is for the implementor of the lock, it simplifies the implementation of the lock, shielding the synchronization state management, thread queuing, waiting and wake up and other low-level operations. This provides a good separation of the areas that consumers and implementers need to focus on.

Internally, AQS maintains a shared resource state, with a built-in FIFO to queue up threads to acquire resources. The queue consists of nodes one by one, each of which maintains a prev reference and a next reference to its precursor and successor, respectively, forming a double-ended bidirectional linked list.

Meanwhile, the waiting queue related to Condition and Node type are also Node, forming a one-way linked list.

53. Outline volatile

The volatile keyword serves two main purposes:

Multithreading is mainly about visibility and atomicity. Using volatile to modify variables ensures that they are visible across multiple threads. That is, every time a volatile variable is read, it must be the latest data. Volatile, however, does not guarantee atomicity for any individual volatile read/write, but compounds such as ++ do not guarantee atomicity.

In order to get better performance, the instructions will be reordered at the bottom of the code, and some unexpected problems may occur under multithreading. Using volatile disables reordering, which, of course, reduces code execution efficiency.

In memory semantics, when a volatile variable is written, the JMM flusher the shared value of the thread’s local memory to main memory, and when a volatile variable is read, the JMM invalidates the thread’s local memory. The thread will next read the shared variable from main memory.

In Java, for volatile variables, the compiler inserts a memory barrier into the instruction sequence when generating the bytecode to prevent certain types of processor reordering problems, forcing flusher, and reads.

Implementationally, volatile variables are prefixed with “lock:”. It is not a memory barrier, but it can do something similar. Lock locks the CPU bus and cache, which can be understood as a CPU instruction level Lock.

At the same time, this instruction will write the current processor cache row directly to the system memory, and this write back to memory will invalidate the other CPU cache of the address of the data.