Java Concurrent Programming interview questions

Posted by maGGot_H on Mon, 10 Jan 2022 12:14:50 +0100

Has Synchronized been used? What is its principle?

Synchronized yes jvm The bottom layer is an object-based monitor monitor Implemented.

cover synchronize Modified code is found after decompilation. It is passed at the beginning and end of the code monitorenter and monitorexit Implemented.

When the virtual machine executes to monitorenter When, the thread attempts to get the name of the object monitor Lock, based on monitor Lock, and produced a lock counter concept.

When executed to monitorenter If the object is not locked or the current thread already holds the object lock, the lock counter+1. 

When executed monitorexit Lock counter for this object when-1,When lock counter=0 When, the thread releases the object lock permission, and other blocking threads can obtain the object lock permission.

You just mentioned obtaining the lock of the object. What is this "lock"? How to determine the lock of an object?

What is reentrant and why is Synchronized a reentrant lock?

Reentrant:
  If a program or subroutine can be "interrupted at any time", then the operating system schedules execution   Another piece of code, which calls the subroutine "no error", is called reentrant  (reentrant or re
-entrant)of

  In short, when a thread holds a lock, it will be blocked when other threads try to obtain the lock;
  When this thread attempts to obtain the lock it holds, if it succeeds, it indicates that the lock is reentrant, otherwise it is not reentrant. synchronized How to achieve reentrant:   synchronized After the keyword is compiled, it will be formed before and after the synchronization block   monitorenter and monitorexit These two bytecode instructions. One meter is maintained inside each lock object   The initial value of the counter is 0, which means that any thread can obtain the lock and execute the corresponding method.   According to the requirements of the virtual machine specification, the monitorenter Command, first try to get the object's   Lock. If the object is not locked, or if the current thread already owns the lock of that object, count the value of the lock   Counter plus 1, corresponding, in execution monitorexit The lock counter is decremented by 1 when the command is issued. When the counter is 0   When, the lock is released. If the acquisition of the object lock fails, the current thread will block and wait until the object lock   Released by another thread.

What optimizations have VM made for Java's native locks?

Spin lock:
stay java6 Before, monitor All implementations depend on the mutex of the underlying operating system.
because java The thread and the thread of the underlying operating system are mapped, so the thread suspension and wake-up are required
 It is too expensive to interact with the operating system from user mode to kernel mode.
One optimization method is to use spin lock: because most of the shared data is locked for a short time
 It's not cost-effective to suspend and wake up threads between spinlocks jdk1.4 introduce,1.6 Default on, spin, etc
 Although waiting avoids the overhead of thread switching, spinning threads take up processor time, so if the lock is locked
 If the occupied time is very short, the spin waiting effect will be very good. On the contrary, if the lock is occupied for a long time, then
 Spinning threads will only be consumed in vain CPU resources.

Therefore, the spin waiting time must have a certain limit. If it exceeds the limit, it is still not successfully obtained
 Lock, the thread should be suspended (blocked). The default value for spin count is 10 Times.

Adaptive spin lock:

stay JDK 1.6 Adaptive spin lock is introduced.
Adaptive means that the spin time is no longer fixed, but determined by the previous spin time on the same lock and the state of the lock owner.
If on the same lock object, the spin wait has just successfully obtained the lock, and the thread holding the lock is running, the virtual machine will think that the spin is likely to succeed again, and then it will allow the spin wait to last for a relatively longer time, such as 100 cycles.
If the spin is rarely successfully obtained for a lock, the spin process may be omitted when acquiring the lock in the future to avoid wasting processor resources.

Lock elimination:

When dynamically compiling synchronous blocks, JIT The compiler can use a method called escape analysis( Escape Analysis)To determine whether the lock object used by the synchronization block can only be accessed by one thread without being published to other threads. This cancels the synchronization of this part of the code.
Lock elimination: refers to the elimination of locks that require synchronization in some code but are detected that there is no shared data competition when the virtual machine real-time compiler runs. Mainly based on escape analysis.

Lock coarsening:

When JIT The compiler finds that a series of continuous operations repeatedly lock and unlock the same object. Even when the lock operation occurs in the loop body, the scope of lock synchronization will be spread (coarsened) to the outside of the whole operation sequence.
When writing code, it is always recommended to limit the scope of the synchronization block (lock granularity) as small as possible (only synchronize in the actual scope of shared data). This is to minimize the number of operations to be synchronized. If there is lock competition, the thread waiting for the lock can get the lock as soon as possible.
Lock granularity: do not lock irrelevant code.

Lock coarsening: if it can be executed at one time, do not lock it multiple times

Why is Synchronized an unfair lock?

synchronized A non fair lock is used and cannot be set. This is because the throughput of non fair locks is greater than that of fair locks, and it is the basic choice of thread scheduling in mainstream operating systems, so this is also true synchronized Reasons for using unfair locks.

What are lock elimination and lock coarsening?

Lock elimination:
When dynamically compiling synchronous blocks, JIT The compiler can use a method called escape analysis( Escape Analysis)To determine whether the lock object used by the synchronization block can only be accessed by one thread without being published to other threads. This cancels the synchronization of this part of the code.
Lock elimination: refers to the elimination of locks that require synchronization in some code but are detected that there is no shared data competition when the virtual machine real-time compiler runs. Mainly based on escape analysis.

Lock coarsening: When JIT The compiler finds that a series of continuous operations repeatedly lock and unlock the same object. Even when the lock operation occurs in the loop body, the scope of lock synchronization will be spread (coarsened) to the outside of the whole operation sequence. When writing code, it is always recommended to limit the scope of the synchronization block (lock granularity) as small as possible (only synchronize in the actual scope of shared data). This is to minimize the number of operations to be synchronized. If there is lock competition, the thread waiting for the lock can get the lock as soon as possible. Lock granularity: do not lock irrelevant code.
Lock coarsening purpose: if it can be executed at one time, do not lock it for multiple times

Why is Synchronized a pessimistic lock? What is the implementation principle of optimistic lock? What is CAS and what are its characteristics?

Synchronized Obviously, it is a pessimistic lock, because its concurrency strategy is pessimistic: no matter whether there will be competition, any data operation must be locked, user state core state conversion, maintaining lock counters and checking whether blocked threads need to be awakened.

Optimistic lock principle: operate first. If there is no other thread to requisition data, the operation will succeed; If the shared data is requisitioned and conflicts arise, other compensation measures shall be taken.
Many implementations of this optimistic concurrency strategy do not require thread suspension, so it is called non blocking synchronization.

The core algorithm of optimistic lock is CAS(CompareandSwap,Compare and swap), which involves three operands: memory value, expected value, and new value. Modify the memory value to the new value if and only if the expected value is equal to the memory value. The logic of this treatment is,
First, check whether the value of a block of memory is the same as that I read before. If it is different, it means that the memory value has been changed by other threads during the period. Discard this operation. Otherwise, it means that no other thread operates on this memory value during the period. You can set the new value to this block of memory.

java.util.concurrent Medium AtomicInteger The bottom layer is also based on CAS Algorithm implementation.

that CAS What is the underlying implementation based on?

CAS->call Native Method through C++ -> Through assembly language local cmpex Command implementation. In short, CAS The most important thing is to pass cpu Implementation of mutex based on

Optimistic lock must be good?

not always. Compared with pessimistic lock, optimistic lock predicts that the shared data will not change, which is suitable for
 For the scenario with more reads and less writes, if it is a scenario with more writes, it may be due to the number of errors when verifying the predicted value and the actual memory value
 The data is frequently changed, resulting in the thread constantly in the "get memory value" state->change a value->Judgment value->Get memory value.

How is the implementation principle of reentrant lock different from that of Synchronized?

Reentrant:
  From the name, ReenTrantLock It literally means re-entry lock, in fact synchronized The lock used by the keyword is also reentrant, and there is little difference between the two. Both of them do not enter the same thread once, and the lock counter increases by 1,
  Therefore, the lock cannot be released until the counter of the lock drops to 0. Lock implementation:   Synchronized Is dependent on JVM Implemented, and ReenTrantLock yes JDK To put it bluntly, it is similar to the difference between the operating system to control the implementation and the user's own code implementation. The implementation of the former is relatively difficult to see, and the latter has direct source code for reading. Performance differences:   stay Synchronized Before optimization, synchronized The performance is better than ReenTrantLock Much worse, but since Synchronized With the introduction of bias lock and lightweight lock (spin lock), their performance is almost the same. When both methods are available,
  Officials even recommend it synchronized,actually synchronized I feel like I can use it for reference ReenTrantLock Medium CAS Technology. They all try to solve the locking problem in the user state to avoid thread blocking in the kernel state. Functional differences: Convenience: obviously Synchronized The use of is more convenient and concise, and the compiler ensures the locking and release of the lock ReenTrantLock Manual declaration is required to add and release locks. In order to avoid deadlock caused by forgetting to release locks manually, it is best to finally Release lock declared in. Fine granularity and flexibility of locks: obviously ReenTrantLock be better than Synchronized ReenTrantLock Unique capabilities:
1.ReenTrantLock You can specify whether it is a fair lock or a non fair lock. and synchronized Can only be unfair locks. The so-called fair lock is that the thread waiting first obtains the lock first. 2.ReenTrantLock Provides a Condition(Condition) class, which is used to wake up the threads that need to wake up, not like synchronized Either wake up one thread randomly or wake up all threads. 3.ReenTrantLock Provides a mechanism that can interrupt threads waiting for locks lock.lockInterruptibly()To implement this mechanism. ReenTrantLock Principle of implementation: In short, ReenTrantLock The implementation of is a spin lock, which is called through a loop CAS Operation to achieve locking. Its performance is better because it avoids the blocking state that makes the thread enter the kernel state.
   Trying to avoid the thread from entering the blocking state of the kernel is the key to analyze and understand the lock design. Under what circumstances ReenTrantLock: If you need to achieve ReenTrantLock Three unique features of.

So please talk about AQS framework?

Please compare the similarities and differences between Synchronized and ReentrantLock in as much detail as possible.

ditto

How does ReentrantLock achieve reentrancy?

ReentrantLock Internal classes are used internally Sync To manage locks, so the real way to obtain locks is by Sync Implementation class control. Sync There are two implementations: NonfairSync(Unfair locks) and FairSync(Fair lock).
Sync By inheritance AQS Implementation, in AQS One is maintained in private volatile int state To count the reentry times, avoiding the efficiency problem caused by frequent holding and release operations.

  ReentrantLock Synchronizer is internally customized Sync(Sync Both realized AQS,Again AOS,and AOS It provides a way to hold a mutex lock, which is actually passed when adding a lock CAS Algorithm, put the thread object into a two-way linked list, and look at the current dimension every time you get the lock    The thread protected ID And the thread of the current request ID Whether it is the same, the same can be re entered.

ReentrantLock source code

// Sync Inherit from AQS
abstract static class Sync extends AbstractQueuedSynchronizer {
  ...
}
// ReentrantLock The default is a non fair lock
public ReentrantLock() {
        sync = new NonfairSync();
 }
// Can be passed to the constructor true To achieve fair lock
public ReentrantLock(boolean fair) {
    sync = fair ? new FairSync() : new NonfairSync();
}

Thread lock grabbing process (fair lock):

protected final boolean tryAcquire(int acquires) {
        // The thread that currently wants to acquire the lock
        final Thread current = Thread.currentThread();
        // Current lock status
        int c = getState();
        // state == 0 No thread holds a lock at this time
        if (c == 0) {
            // Although the lock can be used at this moment, it is a fair lock. Since it is fair, we must pay attention to first come, first served,
            // See if anyone else has been in the queue for a long time
            if (!hasQueuedPredecessors() &&
                // If no thread is waiting, use CAS Try it and get the lock when you succeed,
                // If it fails, it can only explain one problem. Just at almost the same time, a thread preempted =_=
                // Because there was no one just now, I judged
                compareAndSetState(0, acquires)) {

                // Here is the lock. Mark it and tell you that I have occupied the lock
                setExclusiveOwnerThread(current);
                return true;
            }
        }
          // Will enter this else if Branch, indicating reentry, operation required: state=state+1
        // There is no concurrency problem here
        else if (current == getExclusiveOwnerThread()) {
            int nextc = c + acquires;
            if (nextc < 0)
                throw new Error("Maximum lock count exceeded");
            setState(nextc);
            return true;
        }
        // If you come here, explain the previous if and else if No return true,Description no lock was acquired
        return false;
    }

In addition to ReetrantLock, what concurrency tools have you been exposed to in JUC?

Commonly referred to as concurrent packages( JUC)that is java.util.concurrent And its sub packages, centralized Java Various basic tool classes of concurrency mainly include the following aspects:

  1,Provided CountDownLatch,CyclicBarrier,Semaphore Wait, than Synchronized More advanced, it can realize more rich synchronization structure of multi-threaded operation.

  2,Provided ConcurrentHashMap,Orderly ConcunrrentSkipListMap,Or thread safe dynamic arrays can be implemented through a snapshot mechanism CopyOnWriteArrayList And other lines
 A safe container.

  3,Provided ArrayBlockingQueue,SynchorousQueue Or specific scenarios PriorityBlockingQueue Etc., various concurrent queue implementations.

  4,Powerful Executor Framework, you can create various types of thread pools, schedule task runs, etc.

*Talk about ReadWriteLock and StampedLock

although ReentrantLock and Synchronized Simple and practical, but there are certain limitations in behavior, either not occupied or exclusive. In practical application scenarios, sometimes a large number of competing write operations are not required, but concurrent reads are mainly required. In order to further optimize the granularity of concurrent operations,
Java A read-write lock is provided. The read-write lock is based on the principle that multiple read operations do not need to be mutually exclusive. If the read lock attempts to lock, the write lock is held by a thread, the read lock will not be obtained, and the other party has to wait for the end of the operation, so as to automatically ensure that controversial data will not be read. ReadWriteLock It represents a pair of locks. The following is a data structure based on read-write lock. When the amount of data is large, there are more concurrent reads and fewer concurrent writes, it can show its advantages over the pure synchronous version. Read write locks look better than Synchronized The granularity of seems to be finer, but in practical application, its performance is not satisfactory, mainly because of the relatively large overhead. So, JDK Introduced later StampedLock,While providing similar read-write locks, it also supports optimized read mode.
The optimized read operation is based on the assumption that in most cases, the read operation will not conflict with the write operation. The logic is to try to modify it first and then pass it validate Method to confirm whether the write mode is entered. If not, the overhead is successfully avoided;If entered, an attempt is made to acquire a read lock.

How to synchronize Java threads with each other? What synchronizers have you known? Please introduce them separately

JUC There are three main members of the synchronizer in:CountDownLatch,CyclicBarrier and Semaphore,Through them, the function of cooperation between many threads can be easily realized.

CountDownLatch It is called countdown, which allows one or more threads to wait for some operations to complete.

CyclicBarrier It is called loop fence. It enables a group of threads to wait to a certain state and then execute all at the same time. When all waiting threads are released, CyclicBarrier Can be reused. CyclicBarrier A typical application scenario is to wait for the end of a concurrent thread.
CyclicBarrier The main method is await(),await()Each time it is called, the count decreases by 1,And block the current thread. When the count is reduced to 0, the blocking is released, and all are here CyclicBarrier The thread blocked above starts running.
After that, if you call again await. ,The count will become N-1,A new round of start, this is Cyclic The meaning of. CyclicBarrier.await. With a return value, it is used to indicate the number of the current thread arriving at this Barrier Thread.

Semaphore, Java The semaphore implementation of version is used to control the number of threads accessed at the same time to limit the access to general resources. Its principle is through acquire. Get a license, wait if not, and release. Release a license.
If Semaphore The value of is initialized to 1,Then a thread can pass through acquire Entering a mutex state is essentially very similar to a mutex lock. But the difference is also very obvious. For example, mutexes have holders, while for Semaphore Although this counter structure has similar functions,
But in fact, there is no real holder unless we expand the packaging.

CountDownLatch instance code:

package com.atguigu.thread;
 
import java.util.concurrent.CountDownLatch;
 
 
/**
 * 
 * @Description:
 *  *Let some threads block until another thread completes a series of operations.
 * 
 * CountDownLatch There are two main methods. When one or more threads call the await method, these threads will block.
 * Other threads calling the countDown method will reduce the counter by 1 (the thread calling the countDown method will not block),
 * When the value of the counter becomes 0, the thread blocked by the await method will wake up and continue to execute.
 * 
 * Explanation: after six students leave the classroom one after another, the students on duty can close the door.
 * 
 * main The main thread must wait for the first six threads to complete all their work before it can start 
 */
public class CountDownLatchDemo
{
   public static void main(String[] args) throws InterruptedException
   {
         CountDownLatch countDownLatch = new CountDownLatch(6);
       
       for (int i = 1; i <=6; i++) //6 The students who went to self-study did not leave the classroom at the same time
       {
          new Thread(() -> {
              System.out.println(Thread.currentThread().getName()+"\t Classmate No. 1 left the classroom");
              countDownLatch.countDown();
          }, String.valueOf(i)).start();
       }
       countDownLatch.await();
       System.out.println(Thread.currentThread().getName()+"\t****** The monitor closed the door and left, main Thread is the monitor");
          
   }
 
 
}

CyslicBarrier instance code:

package com.atguigu.thread;
 
import java.util.concurrent.BrokenBarrierException;
import java.util.concurrent.CyclicBarrier;
 
/**
 * 
 *
 * CyclicBarrier
 * Literally means a Barrier that can be used cyclically. What it has to do is,
 * When a group of threads reaches a barrier (also known as a synchronization point), they are blocked,
 * The barrier will not open until the last thread reaches the barrier, and all
 * The thread blocked by the barrier will continue to work.
 * The thread enters the barrier through the await() method of CyclicBarrier.
 * 
 * Collect 7 dragon balls to summon the dragon
 */
public class CyclicBarrierDemo
{
  private static final int NUMBER = 7;
  
  public static void main(String[] args)
  {
     //CyclicBarrier(int parties, Runnable barrierAction) 
     
     CyclicBarrier cyclicBarrier = new CyclicBarrier(NUMBER, ()->{System.out.println("*****Collect 7 dragon balls to summon the divine dragon");}) ;
     
     for (int i = 1; i <= 7; i++) {
       new Thread(() -> {
          try {
            System.out.println(Thread.currentThread().getName()+"\t Star Dragon beads are collected ");
            cyclicBarrier.await();
          } catch (InterruptedException | BrokenBarrierException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
          }
       
       }, String.valueOf(i)).start();
     }
     
 
  }
}

Semphore instance code:

package com.atguigu.thread;
 
import java.util.Random;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;
 
/**
 * 
 * @Description: TODO(The function of this class is described in one sentence)  
 * 
 * In terms of semaphores, we define two operations:
 * acquire(Get) when a thread calls the acquire operation, it either obtains the semaphore successfully (semaphore minus 1),
 *             Either wait until a thread releases a semaphore or times out.
 * release(Release) actually increases the value of the semaphore by 1, and then wakes up the waiting thread.
 * 
 * Semaphores are mainly used for two purposes: one is for mutually exclusive use of multiple shared resources, and the other is for controlling the number of concurrent threads.
 */
public class SemaphoreDemo
{
  public static void main(String[] args)
  {
     Semaphore semaphore = new Semaphore(3);//Simulate 3 parking spaces
     
     for (int i = 1; i <=6; i++) //Simulate 6 cars
     {
       new Thread(() -> {
          try 
          {
            semaphore.acquire();
            System.out.println(Thread.currentThread().getName()+"\t Grabbed the parking space");
            TimeUnit.SECONDS.sleep(new Random().nextInt(5));
            System.out.println(Thread.currentThread().getName()+"\t------- leave");
          } catch (InterruptedException e) {
            e.printStackTrace();
          }finally {
            semaphore.release();
          }
       }, String.valueOf(i)).start();
     }
     
  }
}

*CyclicBarrier and CountDownLatch look very similar. Please compare them?

Their behaviors are similar to each other. The main differences are:

  1,CountDownLatch It can't be reset, so it can't be reused, CyclicBarrier Without this limitation, it can be reused.

  2,CountDownLatch The basic combination of operations is countDown/await,call await Thread blocking wait countDown Enough times, whether you are in one thread or multiple threads countDown,As long as the number of times is enough.
  CyclicBarrier The basic combination of operations is await,When all partners call await,Will continue the task and reset automatically. CountDownLatch The goal is to have one thread wait for another N After a thread reaches a certain condition, it does something by itself(adopt CyclicBarrier The second construction method of public CyclicBarrier(
int parties, Runnable barrierAction),
Doing things in a new thread can achieve the same effect). and CyclicBarrier The goal is to make N Multiple threads wait for each other until all have reached a certain state, and then this N Threads continue to execute their subsequent tasks(adopt CountDownLatch Similar effects can be achieved on some occasions).

How is thread pool implemented in Java?

1,When a task is submitted to the thread pool, first judge whether the number of core threads is full. If the number of core threads is not full, create a thread to execute the task, otherwise enter the next step
2,Judge whether the blocking queue is full. If it is not full, put the task into the blocking queue, otherwise execute the next step
3,Judge whether the number of threads in the thread pool reaches the maximum number of threads. If not, create a new thread to execute the task. Otherwise, start the reject policy.

Several core construction parameters for creating thread pool?

int corePoolSize: Number of core threads
int maximumPoolSize: Maximum number of threads
long keepAliveTime: Thread lifetime
TimeUnit unit: Thread lifetime unit
BlockingQueue<Runnable> workQueue: Blocking queue
ThreadFactory threadFactory: Thread factory
RejectedExecutionHandler handler: Task rejection policy

How are threads created in the thread pool? Is it created with the start of the thread pool from the beginning?

no Thread pool does not start after initialization by default Worker,Wait for a request to start.

Since it is mentioned that different thread pools can be created by configuring different parameters, what are the thread pools implemented by default in Java? Please compare their similarities and differences

1,SingleThreadExecutor Thread pool
  This thread pool has only one core thread working, which is equivalent to a single thread executing all tasks in series. If the only thread ends abnormally, a new thread will replace it. This thread pool ensures that all tasks are executed in the order they are submitted.

2,FixedThreadPool Thread pool
  FixedThreadPool Is a fixed size thread pool with only core threads. Each time a task is submitted, a thread is created until the thread reaches the maximum size of the thread pool. Once the size of the thread pool reaches the maximum, it will remain unchanged. If a thread ends due to execution exception,
  Then a new thread will be added to the thread pool.   FixedThreadPool Most of them are aimed at some very stable and fixed regular concurrent threads, which are mostly used in the server. 3,CachedThreadPool Thread pool

4,ScheduledThreadPool Thread pool
ScheduledThreadPool :The core thread pool is a fixed and unlimited thread pool. This thread pool supports the need to execute tasks regularly and periodically. Create a thread pool that executes tasks periodically. If idle, the non core thread pool will DEFAULT_KEEPALIVEMILLIS Recovery within time.

How do I commit threads in the Java thread pool?

1,execute:  ExecutorService.execute Method receives a thread instance, which is used to execute a task: ExecutorService.execut(Runnable runable)

2,submit:  ExecutorService.submit. Method returns Future Object. Can use isDone()To query Future Whether it has been completed. When the task is completed, it has a result, Can call get. To get the results.
You don't have to isDone. Call directly when checking get(),under these circumstances, get()Will block until the results are ready.

What is the memory model of Java? How do threads in Java see each other's variables?

Java The memory model defines the access rules of each variable in the program, that is, the underlying details of storing variables in and taking them out of memory in the virtual machine.

Java The data in is stored in the main memory. If each thread needs to read and write data, it needs to copy the data in the main memory to the working area of each thread, and then write the data in the working area to the main memory. The main memory notifies other threads using the data to pull the latest data again.

*What are the characteristics of volatile and why it can ensure the visibility of variables to all threads?

keyword volatile yes Java The most lightweight synchronization mechanism provided by virtual machines. When a variable is defined as volatile After that, it has two characteristics:

  1,Ensure the visibility of this variable to all threads. When a thread modifies the value of this variable, the new value can be immediately known to other threads. Ordinary variables can't do this.
  2,Prohibit instruction reordering optimization. Ordinary variables can only guarantee the correct results during the execution of the method, but do not guarantee the execution order of the program code.

Java The memory model defines 8 Inter memory operations:

  lock and unlock
    Identify a variable as the exclusive state of a thread.
    A locked variable is released, and the released variable can only be locked by other threads.

  read and write
    Transfer a variable value from main memory to the working memory of the thread for load. 
    hold store The value of the variable obtained from the working memory is put into the variable in the main memory.

  load and store
    hold read The operation puts the variable value obtained from main memory into the variable copy of working memory.
    Transfer the variable value of working memory to main memory for write. 

  use and assgin
    Pass the working memory variable value to the execution engine.
    Pass the execution engine value to the working memory variable value.

volatile The implementation of is based on these eight inter memory operations, which ensures that a thread volatile The modification of variables must be seen by another thread, which ensures the visibility.

Since volatile can ensure variable visibility between threads, does it mean that operations based on volatile variables are concurrent and safe?

Not at all, volatile It can only ensure the visibility of shared data, not the atomicity of data operations. (although all threads can get the latest results after a thread operation, it is not guaranteed whether many thread operations are overwritten)

Please compare the similarities and differences of volatile Synchronized.

1,Synchronized It can ensure both visibility and atomicity, and volatile Only visibility can be guaranteed, not atomicity.
2,Volatile Modify instance variables and class variables, and Synchronized Modification method and code block
3,volatile Used to prohibit instruction reordering
4,volatile It can be seen as a lightweight version synchronize,If you only assign values to shared variables, use volatile Can.

Please talk about how ThreadLocal solves concurrency security?

ThreadLocal Maintain a copy of variables for each thread and limit the visible range of shared data to the same thread. The implementation principle is ThreadLocal There is one in the class Map,A copy of the variable used to store each thread.

Many people say that you should use ThreadLocal carefully. Talk about your understanding. What should you pay attention to when using ThreadLocal?

Assuming no ThreadLocal Variable deletion in( remove)Or replace, its life cycle will coexist with the thread,If not remove If it is dropped, there is likely to be a memory leak.