How to use synchronized code block

Keywords: Programming Java jvm network

What's the difference between having synchronized or not?

What does synchronized lock as a pessimistic lock?

In the previous two articles, we have known how to use synchronized and the content of lock (instance object and Class object), which has covered the basic content of this keyword. Today, I want to introduce another writing method, which is synchronization code block, which implements a more fine-grained synchronization method. I'll see you next.

First, I will introduce how to write synchronization code block. The general code framework is as follows:

synchronized(xxx) {
    
}

XXX can be this or Object or xxx.class. Next, we will discuss three different locking methods.

this

It means that the current object is locked, just like the original synchronous instance mode.

public class SynchronizedCodeTest {

    public static void main(String[] args) {
        SynchronizedCodeTest synchronizedCodeTest = new SynchronizedCodeTest();
        for (int i = 0; i < 5; i ++) {
            Thread thread = new Thread(() -> {
                synchronizedCodeTest.testSynchronizedCode();
            });
            thread.start();
        }
    }

    int count = 0;
    public void testSynchronizedCode() {
        System.out.printf("%s-testSynchronizedCode-start-count=%s\n", Thread.currentThread().getName(), count);
        synchronized (this) {
            System.out.printf("%s-testSynchronizedCode-synchronized-start-count=%s\n", Thread.currentThread().getName(), count);
            count ++;
            System.out.printf("%s-testSynchronizedCode-synchronized-end-count=%s\n", Thread.currentThread().getName(), count);
        }
        System.out.printf("%s-testSynchronizedCode-end-count=%s\n", Thread.currentThread().getName(), count);
    }

}

Operation result:

We mainly focus on the results of the red box and the blue box. The red box contains the code of synchronization block, and threads are mutually exclusive. However, in the blue box, Thread-0 executes synchronization block, and other thread unsynchronized blocks are also executing. This shows that the granularity of lock is really smaller, and the synchronization block code in the method is mutually exclusive, and unsynchronized block code is not mutually exclusive The final value of count is 5, indicating that only one thread is executing at the same time when the synchronization block is executed.

Let's write another test code to see what is locked by synchronized(this)?

public class SynchronizedCodeTest {

    public static void main(String[] args) {
        for (int i = 0; i < 5; i ++) {
            SynchronizedCodeTest synchronizedCodeTest = new SynchronizedCodeTest();
            Thread thread = new Thread(() -> {
                synchronizedCodeTest.testSynchronizedCode();
            });
            thread.start();
        }
    }
}

Operation result:

If you observe the red box, you can see that the synchronization block does not work at this time, and the count is ultimately 1. It is proved that the synchronized(this) locks the current object, just like the public synchronized void testsynchronized method().

Object

Synchronization code block brings flexibility. It can lock any object we create instead of the current object. Let's take a look at it.


public class SynchronizedCodeTest {

    public static void main(String[] args) {
        Object lock = new Object();
        SynchronizedCodeTest synchronizedCodeTest = new SynchronizedCodeTest(lock);
        for (int i = 0; i < 5; i ++) {
            Thread thread = new Thread(() -> {
                synchronizedCodeTest.testSynchroniedLock();
            });
            thread.start();
        }
    }

    int count = 0;

    Object lock = null;
    public SynchronizedCodeTest(Object lock) {
        this.lock = lock;
    }

    public void testSynchroniedLock() {
        System.out.printf("%s-testSynchroniedLock-start-count=%s\n", Thread.currentThread().getName(), count);
        synchronized (lock) {
            System.out.printf("%s-testSynchroniedLock-synchronized-start-count=%s\n", Thread.currentThread().getName(), count);
            count ++;
            System.out.printf("%s-testSynchroniedLock-synchronized-end-count=%s\n", Thread.currentThread().getName(), count);
        }
        System.out.printf("%s-testSynchroniedLock-end-count=%s\n", Thread.currentThread().getName(), count);
    }

}

Operation result:

In this code, we create a lock object, which is passed as a parameter to the synchronized code test object. We see that in the result, five threads execute serially in the synchronized block code, and the final result of count is 5. This code doesn't see the flexibility brought by the lock object. Let's take a look at another example, change the test code a little, so that each thread has its own synchronized code test object.

public static void main(String[] args) {
	Object lock = new Object();
	for (int i = 0; i < 5; i ++) {
	SynchronizedCodeTest synchronizedCodeTest = new SynchronizedCodeTest(lock);
		Thread thread = new Thread(() -> {
			synchronizedCodeTest.testSynchroniedLock();
		});
		thread.start();
	}
}

Operation result:

As a result, we found that although we create a synchronized codetest object for each thread, no matter how we run, the synchronized code blocks of five threads are executed serially. The reason is that we only create one lock object, and all the lock objects of the five synchronized codetests are the same, so the competitive resources are the same, which leads to this situation. See if it's much more flexible than the synchronization method. In the previous article, we need to use the static synchronization method to synchronize multiple instances. Now we don't need to use the synchronization code block. We just need to lock the same instance object.

In addition, the result of this example is that the count of each instance is ultimately 1, because each synchronized codetest object has its own independent variable count, so threads do not affect each other.

xxx.class

Let's look at the last type of code block lock Class. It has the same function as public static synchronized testsynchronized static(). The only difference is that the lock range of the code block is variable. Let's take a look directly at the code example.

public class SynchronizedCodeTest {

    public static void main(String[] args) {
        for (int i = 0; i < 5; i ++) {
            SynchronizedCodeTest synchronizedCodeTest = new SynchronizedCodeTest();
            Thread thread = new Thread(() -> {
                synchronizedCodeTest.testSynchronizedCodeClass();
            });
            thread.start();
        }
    }

    int count = 0;
    public void testSynchronizedCodeClass() {
        System.out.printf("%s-testSynchronizedCodeClass-start-count=%s\n", Thread.currentThread().getName(), count);
        synchronized (SynchronizedCodeTest.class) {
            System.out.printf("%s-testSynchronizedCodeClass-synchronized-start-count=%s\n", Thread.currentThread().getName(), count);
            count ++;
            System.out.printf("%s-testSynchronizedCodeClass-synchronized-end-count=%s\n", Thread.currentThread().getName(), count);
        }
        System.out.printf("%s-testSynchronizedCodeClass-end-count=%s\n", Thread.currentThread().getName(), count);
    }

}

Operation result:

Each thread has its own instance, but locking Class will make the synchronization block of each thread instance Object execute serially. This result is the same as locking the same Object object by multiple instances above. Personally, I prefer to lock the same Object object instead of Class Object.

summary

This article introduces three ways of using synchronized code block, and introduces their usage and differences in detail. Simple columns and tables.

type How to use Scope of locking action
this synchronized(this){} Lock the current instance object
object synchronized(lock){} Lock other instance objects, more flexible
xxx.class synchronized(xxx.class){} Lock Class object

In total, three articles have been used to introduce the specific usage of synchronized, mainly because some of the previous articles immediately entered the Java source code and JVM source code, which made many friends feel a bit laborious, and even some friends did not come in to have a look at the title. So this time, I will introduce some relatively simple usages, let you know first, and the following articles will be more in-depth I hope you can also read the articles on synchronized principle, which will be very fruitful.

It's not easy to be original. Please forward it and watch it.

Recommended reading

What does synchronized lock as a pessimistic lock?

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

Understand the priority of Java threads and the priority of the corresponding operating system, or you will step on the pit

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?

Do you forget and forget 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!

Posted by Full-Demon on Mon, 27 Apr 2020 18:55:23 -0700