Network Security Internet Technology Development Database Servers Mobile Phone Android Software Apple Software Computer Software News IT Information

In addition to Weibo, there is also WeChat

Please pay attention

WeChat public account

Shulou

How to use synchronized to realize multi-thread lock in Java

2025-02-21 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Internet Technology >

Share

Shulou(Shulou.com)06/02 Report--

This article introduces how to use synchronized to achieve multi-thread lock in Java, the content is very detailed, interested friends can refer to, hope to be helpful to you.

Four ways of using synchronized

Decorated code block: the decorated code block is called the synchronous statement block, and its scope is the code enclosed in curly braces {}, acting on the calling object.

Decorated method: the modified method is called synchronous method, and its function scope is the whole method, which acts on the calling object > Note: when synchronized modifies the method, it must be called explicitly, if there is no explicit call, for example, when the subclass overrides the method without explicitly adding synchronized, then there will be no locking effect.

Modify static methods: their scope is the entire static method, which acts on all objects

Modifier class: its scope is the parenthesized part after the synchronized (for example: test.class), acting on all objects

Do object locks and class locks affect each other?

Object locks: all objects in Java contain a mutex, which is automatically acquired and released by JVM. The thread acquires the lock of the object when it enters the synchronized method. Of course, if a thread has already acquired the lock of the object, the current thread will wait; if the synchronized method returns normally or terminates with an exception, JVM will automatically release the object lock. This also shows one of the benefits of locking with synchronized. When the method throws an exception, the lock can still be automatically released by JVM.

Class locks: object locks are used to control synchronization between instance methods, and class locks are used to control synchronization between static methods (or static variable mutexes). In fact, class lock is only a conceptual thing, it is not real, it is only used to help us understand the difference between locking instance methods and static methods. The java class may have many objects, but there is only one Class object, that is, the Class object of the class is shared between different instances of the class. The Class object is really just a java object, just a little special. Because each java object has a mutex, the static method of the class requires a Class object. So the so-called class lock is just the lock of the Class object.

The class lock and the object lock are not the same thing, one is the lock of the Class object of the class, the other is the lock of the instance of the class. That is, when one thread accesses the static synchronized, another thread is allowed to access the object's instance synchronized method. The reverse is also true because the locks they need are different.

The corresponding experimental code is as follows:

@ Slf4jpublic class SynchronizedExample {/ / decorates a code block public void test1 (int j) {synchronized (this) {for (int I = 0; I)

< 10; i++) { log.info("test1 {} - {}", j, i); } } } // 修饰一个方法 public synchronized void test2(int j) { for (int i = 0; i < 10; i++) { log.info("test2 {} - {}", j, i); } } // 修饰一个类 public static void test3(int j) { synchronized (SynchronizedExample.class) { for (int i = 0; i < 10; i++) { log.info("test3 {} - {}", j, i); } } } // 修饰一个静态方法 public static synchronized void test4(int j) { for (int i = 0; i < 10; i++) { log.info("test4 {} - {}", j, i); } } public static void main(String[] args) { SynchronizedExample example1 = new SynchronizedExample(); SynchronizedExample example2 = new SynchronizedExample(); ExecutorService executorService = Executors.newCachedThreadPool(); executorService.execute(() ->

{example1.test2 (1);}); executorService.execute (()-> {example2.test2 (2);});}}

Before JDK1.6, synchronized was called a heavyweight lock (a heavyweight lock uses mutexes to control access to resources). By decompiling into bytecode instructions, you can see that synchronized forms two bytecode instructions, monitorenter and monitorexit, before and after the synchronization block. According to the requirements of the virtual machine specification, when executing the monitorenter instruction, we should first try to acquire the lock of the object. If the object is not locked, or the current thread already has a lock on that object, increase the lock counter by 1, and the lock calculator is subtracted by 1 when the monitorexit instruction is executed. When the counter is 0, the lock is released, and notify notifies all waiting threads. The threads of Java are mapped to the native threads of the operating system, so if you want to block or wake up a thread, you need the help of the operating system, which requires user mode and kernel mode switching, and a large number of state transitions take a lot of processor time.

Optimization of synchronized

A large number of optimizations have been introduced to lock implementation in JDK1.6:

Lock coarsening (Lock Coarsening): extends multiple consecutive locks into a larger range of locks to reduce the performance loss caused by frequent mutex synchronization.

Lock removal (Lock Elimination): when the JVM just-in-time compiler is running, through escape analysis, the lock can be removed if it is determined that all data on the heap in a piece of code will not escape and has never been accessed by other threads.

Biased lock (Biased Locking): the goal is to eliminate synchronization primitives without data contention. Use the CAS record to get its thread. The next time the same thread enters, it is biased towards that thread without any synchronization.

Adaptive spin (Adaptive Spinning): in order to avoid thread frequently suspending, resuming state switching consumption. The thread enters the spin state. JDK1.6 introduces adaptive spin. The spin time can be reduced according to the dynamic change of the previous lock spin time and thread state.

Lightweight lock (Lightweight Locking): avoid heavyweight mutex locks without multithreaded competition, and only rely on an CAS atomic instruction to acquire and release locks.

After JDK1.6, synchronized is no longer a heavyweight lock, and the lock state changes to the following four states:

No lock-> bias lock-> lightweight lock-> heavyweight lock

State adaptive spin lock of lock

Most of the time, the locked state of shared data only lasts for a short period of time, and it is not worth suspending and restoring threads for this time. If we can get two or more threads to execute in parallel at the same time, we can ask the later thread that requests the lock to "wait a minute" without giving up the processor's execution time to see if the thread holding the lock will release the lock soon. This technique is called spin locking.

The spin wait time must be limited, and if the spin exceeds the limit number of times and still does not acquire the lock, the thread should be suspended. An adaptive spin lock is introduced in JDK1.6, which means that the spin time is no longer fixed, but is determined by the spin time of the previous time on the same lock and the state of the lock owner.

> the so-called spin does not block when it cannot be obtained, but waits in place for a while and tries again (of course, the number of times or time is limited). It costs the cost of kernel state switching at the expense of CPU. With the help of adaptive spin, a relative balance can be found between the loss of CPU time slices and the switching overhead of kernel state, thus improving performance.

Bias lock

In most cases, locks are not only not multithreaded, but are always acquired by the same thread multiple times. Biased locks are introduced to make it cheaper for threads to acquire locks. When a thread accesses the synchronized block and acquires the lock, the thread ID of the lock bias is stored in the lock record of the object header. Later, the thread does not need to lock and unlock the synchronized block when entering and exiting the block. It is simply necessary to test whether the biased lock pointing to the current thread is stored in the MarkWord of the object header. If the test is successful, the thread has acquired the lock. If the test fails, you need to test again whether the identity of the biased lock in MarkWord is set to 1 (indicating that it is currently biased): if it is not set, the CAS contention lock is used; if so, try to use CAS to point the object header bias lock to the current thread, and if it fails, upgrade the lightweight lock.

Lightweight lock

If the bias lock allows only one thread to acquire the lock, then the lightweight lock allows multiple threads to acquire the lock, but only allows them to acquire the lock sequentially, without competition, that is, if the lock fails, the steps for lightweight locking are as follows:

Thread 1 before executing the synchronized code block, JVM will first create a space in the stack frame of the current thread to store the lock record, and then copy the MarkWord in the object header to the lock record, officially called DisplacedMarkWord. The thread then attempts to use CAS to replace the MarkWord in the object header with a pointer to the lock record. If successful, the lock is obtained and proceed to step 3). If it fails, perform step 2)

The thread spins, and if the spin succeeds, the lock is acquired. Proceed to step 3). If the spin fails, it expands to a heavyweight lock and changes the lock flag bit to 10, and thread blocking proceeds to step 3)

The holding thread of the lock executes the synchronization code, and the CAS replacement MarkWord successfully releases the lock. If the CAS succeeds, the process ends, and the CAS fails to execute step 4)

The failure of CAS execution indicates that a thread attempts to acquire the lock and spin fails, and the lightweight lock is upgraded to a heavyweight lock. After the lock is released, the waiting thread will be awakened.

Weight lock

During the spinning process, the spinning thread successfully acquires the resource (that is, the thread of the previously acquired resource completes the execution and releases the shared resource), then the whole state is still in the state of lightweight lock, and if the spin fails, it enters the state of heavyweight lock. At this time, the spinning thread blocks, waits for the previous thread to finish execution and wakes itself up, and needs to switch from the user mode to the kernel mode. When the competition is fierce, the thread goes directly into the blocking state. However, in the higher version of JVM, it will not immediately enter the blocking state, but will spin for a while to see if the lock can be acquired. If not, it will enter the blocking state. )

Summary

It can be summarized as follows:

Only one thread enters the lock area, and the lock state is biased towards the lock

Multiple threads enter the locking area alternately, and the lock state may be lightweight.

Multiple threads enter the locking area at the same time, and the lock state may be a heavy lock.

On how to use synchronized in Java to achieve multi-thread lock is shared here, I hope the above content can be of some help to you, can learn more knowledge. If you think the article is good, you can share it for more people to see.

Welcome to subscribe "Shulou Technology Information " to get latest news, interesting things and hot topics in the IT industry, and controls the hottest and latest Internet news, technology news and IT industry trends.

Views: 0

*The comments in the above article only represent the author's personal views and do not represent the views and positions of this website. If you have more insights, please feel free to contribute and share.

Share To

Internet Technology

Wechat

© 2024 shulou.com SLNews company. All rights reserved.

12
Report