Continue with synchronized, last article What's the difference between having synchronized or not? We have learned that synchronized is used when multiple threads compete for the same resource concurrently. In this article, we will learn what is locked by synchronized as a pessimistic lock?
Lock instance object
In the last article, we have code samples of lock instance objects, but we didn't elaborate on this concept at that time. Let's write another code to test it. The code logic is as follows: we write two synchronized instance methods and let five threads execute two methods randomly. The code is as follows:
When there is only one instance object:
public class SynchronizedTest { public static void main(String[] args) { SynchronizedTest synchronizedTest = new SynchronizedTest(); for (int i = 0; i < 5; i++) { int thisi = i; Thread thread = new Thread(() -> { if (thisi % 2 == 0) { synchronizedTest.testSynchronizedMethod1(); } else { synchronizedTest.testSynchronizedMethod2(); } }); thread.start(); } } public synchronized void testSynchronizedMethod1() { System.out.printf("%s-testSynchronizedMethod1-start-count=%s\n", Thread.currentThread().getName(), count); count ++; System.out.printf("%s-testSynchronizedMethod1-end-count=%s\n", Thread.currentThread().getName(), count); } public synchronized void testSynchronizedMethod2() { System.out.printf("%s-testSynchronizedMethod2-start-count=%s\n", Thread.currentThread().getName(), count); count ++; System.out.printf("%s-testSynchronizedMethod2-end-count=%s\n", Thread.currentThread().getName(), count); } }
Operation result:
There are 5 threads in this code competing for a synchronized test resource, so they can only run serially. Here we use 2 methods to make it clear that the object is locked, not a method in the lock object. If it is a lock method, then the Thread-0 calls testSynchronizedMethod1 method and the Thread-1 calls testSynchronizedMethod2 method will not execute serially and concurrently; however, the result is serial execution, which verifies that it is a lock synchronizedTest object rather than a method. Through the count result, it is clear that the method is executed serially.
One instance object per thread:
public class SynchronizedTest { public static void main(String[] args) { for (int i = 0; i < 5; i++) { SynchronizedTest synchronizedTest = new SynchronizedTest(); int thisi = i; Thread thread = new Thread(() -> { if (thisi % 2 == 0) { synchronizedTest.testSynchronizedMethod1(); } else { synchronizedTest.testSynchronizedMethod2(); } }); thread.start(); } } public synchronized void testSynchronizedMethod1() { System.out.printf("%s-testSynchronizedMethod1-start-count=%s\n", Thread.currentThread().getName(), count); count ++; System.out.printf("%s-testSynchronizedMethod1-end-count=%s\n", Thread.currentThread().getName(), count); } public synchronized void testSynchronizedMethod2() { System.out.printf("%s-testSynchronizedMethod2-start-count=%s\n", Thread.currentThread().getName(), count); count ++; System.out.printf("%s-testSynchronizedMethod2-end-count=%s\n", Thread.currentThread().getName(), count); } }
This code is that each thread has an independent object, and there is no competition between threads, so they do not affect each other. count is also thread independent, so the end result is 1. In order to compare this example with the Class object of the lock Class below, first remember the situation of lock instance object. As long as the lock between threads is not the same instance object, there will be no competition between threads.
Class object of lock class
We will change the original instance method to static static method. The IDE of this code will prompt exceptions. We can ignore the exceptions first and execute successfully.
public class SynchronizedTest { public static void main(String[] args) { for (int i = 0; i < 5; i++) { SynchronizedTest synchronizedTest = new SynchronizedTest(); Thread thread = new Thread(() -> { synchronizedTest.testSynchronizedStaticMethod(); }); thread.start(); } } public static synchronized void testSynchronizedStaticMethod() { System.out.println("testSynchronizedStaticMethod-start-" + Thread.currentThread().getName()); System.out.println("testSynchronizedStaticMethod-end-" + Thread.currentThread().getName()); } }
Code result:
We can see that the execution of 5 threads to testsynchronized static method method is serial execution, which is a little different from the above example. In the above example, 5 instance objects do not affect each other. So you can see that adding static is not a lock instance object, but a lock Class object.
summary
In this article, we talked about two kinds of lock mechanisms in synchronized decorating methods: Lock instance object and lock Class object. Compared with the coarse granularity of lock, the granularity of lock Class object is larger than that of lock instance object.
Synchronization method is the simplest use of synchronized. Next, I will talk about the use of synchronized code block, which reduces the lock granularity to another level. I hope you can read it then.
Recommended reading
What's the difference between having synchronized or not?
Java daemons from the perspective of JVM
Write Java code for many years, and finally debug to the JVM
The latest and simplest OpenJDK13 code compilation of the whole network
The most basic knowledge of thread
The boss told you to stop blocking
You can learn Serial, parallel and concurrent by eating fast food
Make a cup of tea and learn from each other
How much do you know about the process?
Did you forget about the design pattern?
Reply "design mode" in the background, you can get "one story one design mode" e-book
Feel the article useful to help forward & like, thank you!