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

Usage scenario of Java multithread access Synchronized synchronization method

2025-01-28 Update From: SLTechnology News&Howtos shulou NAV: SLTechnology News&Howtos > Development >

Share

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

This article mainly explains the "Java multi-thread access Synchronized synchronization method use scene", the article explains the content is simple and clear, easy to learn and understand, now please follow the editor's ideas slowly in-depth, together to study and learn "Java multi-thread access Synchronized synchronization method use scenario"!

Brief introduction

This article will introduce the access scenarios of seven synchronization methods, and let's see if the multithreaded access synchronization method is thread-safe in these seven cases. These scenarios are often encountered in multithreaded programming, and they are also frequently asked questions during interviews, so whether in theory or in practice, these are all scenarios that multithreaded scenarios must be mastered.

Eight usage scenarios:

Next, let's use the code implementation to determine whether the following scenarios are thread-safe and why.

A synchronous method for two threads to access the same object at the same time

A synchronous method for two threads to access two objects at the same time

A static synchronization method in which two threads access (one or two) objects at the same time.

Synchronous and asynchronous methods for two threads to access (one or two) objects at the same time

Two threads access a synchronous method in the same object, and the synchronous method calls an asynchronous method

Different synchronization methods for two threads to access the same object at the same time

Two threads simultaneously access static synchronized and non-static synchronized methods, respectively

When the synchronization method throws an exception, the JVM automatically releases the lock

Scenario 1: a synchronization method in which two threads access the same object at the same time

Analysis: this situation is the method lock in the classic object lock, in which two threads compete for the same object lock, so they will wait for each other, which is thread-safe.

The synchronization method in which two threads access the same object at the same time is thread safe. one

We have already talked about it in the previous article. Code and detailed explanation in "two ways and principles of synchronized implementation of object locks in Java" in the second part, "method locks", will not be repeated here.

Scenario 2: a synchronization method in which two threads access two objects at the same time

This scenario is the scenario of object lock failure, because the access to the synchronization method of two objects, then the two threads hold the locks of the two threads, so they will not be restricted to each other. The purpose of locking is to make multiple threads compete for the same lock, and in this case, multiple threads no longer compete for the same lock, but hold a lock, so our conclusion is:

It is not thread-safe for two threads to access the synchronization method of two objects at the same time. 1 Code verification: public class Condition2 implements Runnable {/ / create two different objects static Condition2 instance1 = new Condition2 (); static Condition2 instance2 = new Condition2 (); @ Override public void run () {method ();} private synchronized void method () {System.out.println ("thread name: + Thread.currentThread (). GetName () +, run"); try {Thread.sleep (4000);} catch (InterruptedException e) {e.printStackTrace () } System.out.println ("Thread:" + Thread.currentThread (). GetName () +, run end ");} public static void main (String [] args) {Thread thread1 = new Thread (instance1); Thread thread2 = new Thread (instance2); thread1.start (); thread2.start (); while (thread1.isAlive () | thread2.isAlive ()) {} System.out.println (" Test end ");} 12345678910111213141517181920223252627282930 run result:

The two threads execute in parallel, so the thread is not safe.

Follow the official account: programmer Bai Nannan, get the summary interview questions at the end of 2020

Thread name: Thread-0, run start thread name: Thread-1, run start thread: Thread-0, run end thread: Thread-1, run end test end 12345 code analysis:

"here's the problem:" two threads (thread1, thread2), the synchronization method (method ()) that accesses two objects (instance1, instance2), both threads have their own locks, so they can't form a situation in which two threads compete for a lock, so at this time, the method method () modified by synchronized has the same effect as that without synchronized modification (if you don't believe it, remove the synchronized keyword, the result is the same), so method () is just a common method.

"how to solve this problem:" to make the lock effective, simply modify the method () method with static, so that a class lock is formed, and multiple instances (instance1, instance2) compete for a class lock, so that two threads can execute serially. This is what the next scene is going to talk about.

Scenario 3: a static synchronization method in which two threads access (one or two) objects at the same time

This scenario solves the thread unsafe problem in scenario 2, that is, it is implemented with class locks:

The static synchronization method in which two threads access (one or both) objects at the same time is thread-safe. one

With regard to the code implementation and detailed explanation of this method, refer to the second part of the article "two ways and principle Analysis of synchronized implementing Class Lock in Java", which will not be repeated here.

Scenario 4: synchronous and asynchronous methods in which two threads access (one or two) objects at the same time

In this scenario, when one of the two threads accesses the synchronous method and the other accesses the asynchronous method, will the program be executed serially, that is, thread-safe? We can be sure that it is thread-unsafe, and if methods are safe without adding synchronized, then there is no need for synchronous methods. To verify our conclusion:

It is unsafe for two threads to access the synchronous and non-synchronous methods of (one or two) objects at the same time. 1public class Condition4 implements Runnable {static Condition4 instance = new Condition4 (); @ Override public void run () {/ / two threads access synchronous and asynchronous methods if (Thread.currentThread (). GetName (). Equals ("Thread-0")) {/ / thread 0, execute the synchronization method method0 () method0 () } if (Thread.currentThread (). GetName (). Equals ("Thread-1")) {/ / Thread 1, execute the asynchronous method method1 () method1 ();}} / / synchronous method private synchronized void method0 () {System.out.println ("thread name:" + Thread.currentThread (). GetName () + ", synchronous method, run start"); try {Thread.sleep (4000) } catch (InterruptedException e) {e.printStackTrace ();} System.out.println ("Thread:" + Thread.currentThread (). GetName () +, synchronous method, run end ");} / / Common method private void method1 () {System.out.println (" Thread name: "+ Thread.currentThread (). GetName () +, Common method, run start"); try {Thread.sleep (4000) } catch (InterruptedException e) {e.printStackTrace ();} System.out.println ("Thread:" + Thread.currentThread (). GetName () +, common method, run end ");} public static void main (String [] args) {Thread thread1 = new Thread (instance); Thread thread2 = new Thread (instance); thread1.start (); thread2.start () While (thread1.isAlive () | thread2.isAlive ()) {} System.out.println ("end of test");} 123456789101112131415161718192021223242526282930313334353638394041444454647484950:

The two threads are executed in parallel, so they are not thread safe.

Thread name: Thread-0, synchronization method, run start thread name: Thread-1, common method, run start thread: Thread-0, synchronization method, run end thread: Thread-1, common method, run end test end 12345 result analysis

"here's the problem:" method1 is not decorated by synchronized, so it is not affected by locks. Even in the same object, of course, in multiple instances, it will not be affected by the lock. Conclusion:

Asynchronous methods are not affected by other synchronization methods modified by synchronized 1

You may think of a similar scenario in which multiple threads access a synchronous method in the same object, and the synchronous method calls an asynchronous method. Will this scenario be thread-safe?

Scenario 5: two threads access a synchronous method in the same object, and the synchronous method calls an asynchronous method

Let's experiment with this scenario, using two threads to call the synchronization method, calling the normal method in the synchronization method, and then using a thread to call the ordinary method directly to see if it is thread-safe.

Public class Condition8 implements Runnable {static Condition8 instance = new Condition8 (); @ Override public void run () {if (Thread.currentThread (). GetName (). Equals ("Thread-0")) {/ / directly call the ordinary method method2 ();} else {/ / call the synchronous method first, and call the ordinary method method1 () within the synchronous method }} / / synchronization method private static synchronized void method1 () {System.out.println ("thread name:" + Thread.currentThread (). GetName () + ", synchronization method, run start"); try {Thread.sleep (2000);} catch (InterruptedException e) {e.printStackTrace () } System.out.println ("Thread:" + Thread.currentThread (). GetName () +, synchronous method, end of run, start calling normal method "); method2 ();} / / Common method private static void method2 () {System.out.println (" Thread name: "+ Thread.currentThread (). GetName () +, ordinary method, run start"); try {Thread.sleep (4000) } catch (InterruptedException e) {e.printStackTrace ();} System.out.println ("Thread:" + Thread.currentThread (). GetName () +, ordinary method, end of run ");} public static void main (String [] args) {/ / this thread directly calls the ordinary method Thread thread0 = new Thread (instance); / / the two threads directly call the synchronization method Thread thread1 = new Thread (instance); Thread thread2 = new Thread (instance) Thread0.start (); thread1.start (); thread2.start (); while (thread0.isAlive ()) | | thread1.isAlive () | | thread2.isAlive () {} System.out.println ("Test is over") } 12345678910111213141516171819202122232426272829303133343537383940414244446484950515253 run result: thread name: Thread-0, common method, run start thread: Thread-1, synchronization method, run start thread: Thread-1, synchronization method, run end thread: Thread-1, common method, run start thread: Thread-0, common method, run end thread: Thread-1, common method, run end thread name: Thread-2, synchronization method Run start thread: Thread-2, synchronous method, run end, start calling common method thread name: Thread-2, common method, run start thread: Thread-2, common method, run end test end 1234567891011 result analysis:

We can see that the normal method is executed in parallel by two threads and is not thread-safe. Why is that?

Because if an asynchronous method is called directly by any other thread, rather than only when the synchronous method is called, multiple threads execute the asynchronous method in parallel, and the thread is not safe.

When calling an asynchronous method in a synchronous method, if you want to ensure thread safety, you must ensure the entry of the asynchronous method, which only appears in the synchronous method. But this kind of control method is not elegant enough, if the asynchronous method is called directly by unknown people, it will cause the original thread synchronization to be no longer safe. So it is not recommended to use this in a project, but we need to understand the situation, and we need to deal with thread safety in a semantically clear way that makes it clear that this is a synchronous approach.

Therefore, the easiest way is to add the synchronized keyword to the asynchronous method to make it a synchronous method, which becomes "scenario 5: different synchronization methods for two threads accessing the same object at the same time". In this scenario, you can clearly see that the two synchronization methods in the same object, no matter which thread calls, are thread-safe.

So the conclusion is:

Two threads access a synchronous method in the same object, and the synchronous method calls an asynchronous method, which is thread-safe only if no other thread calls the asynchronous method directly. If other threads call asynchronous methods directly, it is not thread-safe. Scenario 6: different synchronization methods for two threads to access the same object at the same time

This scenario is also exploring the scope of object locks, which are all synchronization methods in the object. So, when accessing multiple synchronization methods in the same object, the conclusion is:

It is thread safe when two threads access different synchronization methods of the same object at the same time. 1public class Condition5 implements Runnable {static Condition5 instance = new Condition5 (); @ Override public void run () {if (Thread.currentThread (). GetName (). Equals ("Thread-0")) {/ / thread 0, execute synchronization method method0 () method0 ();} if (Thread.currentThread (). GetName (). Equals ("Thread-1")) {/ / thread 1, execute synchronization method method1 () method1 () }} private synchronized void method0 () {System.out.println ("thread name:" + Thread.currentThread (). GetName () + ", synchronization method 0, run starts"); try {Thread.sleep (4000);} catch (InterruptedException e) {e.printStackTrace ();} System.out.println ("thread:" + Thread.currentThread () .getName () + ", synchronization method 0, run ends") } private synchronized void method1 () {System.out.println ("Thread name:" + Thread.currentThread (). GetName () +, synchronization method 1, run start "); try {Thread.sleep (4000);} catch (InterruptedException e) {e.printStackTrace ();} System.out.println (" Thread: "+ Thread.currentThread (). GetName () +", synchronization method 1, run end ") } / / running result: serial public static void main (String [] args) {Thread thread1 = new Thread (instance); Thread thread2 = new Thread (instance); thread1.start (); thread2.start (); while (thread1.isAlive () | | thread2.isAlive ()) {} System.out.println ("Test over");}} 1234567891011121315161718192021223252627282930313334353638394041424444546:

Is thread safe.

Thread name: Thread-1, synchronization method 1, run start thread: Thread-1, synchronization method 1, run end thread name: Thread-0, synchronization method 0, run start thread: Thread-0, synchronization method 0, run end test ends 12345 result analysis:

The synchronized modifiers of the two methods (method0 () and method1 ()) do not specify a lock object, but the default lock object is the this object, so for the same instance (instance), the lock obtained by two threads is the same lock, and the synchronization method is executed sequentially. This is also a manifestation of the reentrancy of the synchronized keyword.

Scenario 7: two threads access static synchronized and non-static synchronized methods simultaneously

The nature of this scenario is also to explore whether two threads acquire the same lock. Static synchronized methods belong to class locks, lock objects are (* .class) objects, non-static synchronized methods belong to method locks in object locks, and lock objects are this objects. The two threads get different locks, which naturally don't affect each other. Conclusion:

It is not safe for two threads to access static synchronized and non-static synchronized methods at the same time. 1 Code implementation: public class Condition6 implements Runnable {static Condition6 instance = new Condition6 (); @ Override public void run () {if (Thread.currentThread (). GetName (). Equals ("Thread-0")) {/ / thread 0, execute static synchronization method method0 () method0 ();} if (Thread.currentThread (). GetName (). Equals ("Thread-1")) {/ / thread 1, execute non-static synchronization method method1 () method1 () }} / / emphasis: the method modified with static synchronized belongs to the class lock, and the lock object is a (* .class) object. Private static synchronized void method0 () {System.out.println ("thread name:" + Thread.currentThread (). GetName () + ", static synchronization method 0, run starts"); try {Thread.sleep (4000);} catch (InterruptedException e) {e.printStackTrace ();} System.out.println ("thread:" + Thread.currentThread () .getName () + ", static synchronization method 0, run ends") } / / key: the method modified by synchronized belongs to the method lock, and the lock object is the (this) object. Private synchronized void method1 () {System.out.println ("thread name:" + Thread.currentThread (). GetName () + ", non-static synchronization method 1, run start"); try {Thread.sleep (4000);} catch (InterruptedException e) {e.printStackTrace ();} System.out.println ("thread:" + Thread.currentThread (). GetName () + ", non-static synchronization method 1, run end") } / / running result: parallel public static void main (String [] args) {/ / cause of the problem: the lock of thread 1 is a class lock (* .class) object, and the lock of thread 2 is a method lock (this) object, so the locks of the two threads will not affect each other, so they will be executed in parallel. Thread thread1 = new Thread (instance); Thread thread2 = new Thread (instance); thread1.start (); thread2.start (); while (thread1.isAlive () | | thread2.isAlive ()) {} System.out.println ("Test over") } 12345678910111213141516171819202122232526272829303133343536383940414244445464748 run result: thread name: Thread-0, static synchronization method 0, run start thread name: Thread-1, non-static synchronization method 1, run start thread: Thread-1, non-static synchronization method 1, run end thread: Thread-0, static synchronization method 0, run end test ends 12345 scenario 8: after the synchronization method throws an exception, JVM automatically releases the lock

This scenario discusses the scenario in which synchronized releases the lock:

The lock is released only when the synchronization method finishes or when an exception is thrown. one

Therefore, when an exception occurs in one thread's synchronization method, the lock is released and the other thread gets the lock and continues to execute. It does not occur when one thread throws an exception and another thread waits for the lock to be acquired. This is because JVM automatically releases the lock object when the synchronization method throws an exception.

Code implementation: public class Condition7 implements Runnable {private static Condition7 instance = new Condition7 (); @ Override public void run () {if (Thread.currentThread (). GetName (). Equals ("Thread-0")) {/ / thread 0, execute the exception throwing method method0 () method0 ();} if (Thread.currentThread (). GetName (). Equals ("Thread-1")) {/ / thread 1, execute the normal method method1 () method1 () }} private synchronized void method0 () {System.out.println ("thread name:" + Thread.currentThread () .getName () + ", run"); try {Thread.sleep (4000);} catch (InterruptedException e) {e.printStackTrace () } / / in the synchronization method, JVM automatically releases the lock when an exception is thrown, and other threads can acquire the lock System.out.println ("thread name:" + Thread.currentThread (). GetName () + ", throw an exception and release the lock"); throw new RuntimeException ();} private synchronized void method1 () {System.out.println ("thread name:" + Thread.currentThread (). GetName () + ", start running"). Try {Thread.sleep (4000);} catch (InterruptedException e) {e.printStackTrace ();} System.out.println ("Thread:" + Thread.currentThread (). GetName () +, run end ");} public static void main (String [] args) {Thread thread1 = new Thread (instance); Thread thread2 = new Thread (instance); thread1.start (); thread2.start () While (thread1.isAlive () | | thread2.isAlive ()) {} System.out.println ("Test is over") } 12345678910111213141516171819202122232426272829303133343536383940414244444647484950 run result: Thread-0, start thread name: Thread-0, throw exception, release lock thread name: Thread-1, run start Exception in thread "Thread-0" java.lang.RuntimeException at com.study.synchronize.conditions.Condition7.method0 (Condition7.java:34) at com.study.synchronize.conditions.Condition7.run (Condition7.java:17) at java.lang.Thread.run (Thread.java:748) thread: Thread-1 Run end test end 123456789 result analysis:

You can see that the thread is executed serially, indicating that it is thread-safe. Moreover, when an exception occurs, it will not cause a deadlock. JVM will automatically release the lock object of the abnormal thread, and other threads will acquire the lock and continue to execute.

Thank you for your reading, the above is the content of "Java multithread access Synchronized synchronization method usage scenario". After the study of this article, I believe you have a deeper understanding of the problem of Java multithread access Synchronized synchronization method usage scenario, and the specific use situation still needs to be verified in practice. Here is, the editor will push for you more related knowledge points of the article, welcome to follow!

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

Development

Wechat

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

12
Report