Synchronized is a common means of dealing with concurrency in the Java language, and is also affectionately referred to as the “Java built-in lock,” hence its high status. Synchronized, on the other hand, can be used in a variety of ways, with different meanings as it modifies different objects, as we’ll see below.

Synchronized usage

Synchronized can be used to refer to common methods, static methods, and code blocks.

① Modify common methods

/** * synchronized
public synchronized void method(a) {
    / /...
}
Copy the code

Synchronized refers to a method that is synchronized with the object that called it.

② Modify static methods

/** * synchronized
public static synchronized void staticMethod(a) {
    / /...
}
Copy the code

When synchronized decorates static methods, its scope is the entire method, and its scope is any object that calls that class.

③ Decorate code blocks

To reduce the granularity of locking, we can choose to use synchronized to modify a section of a method, as follows:

public void classMethod(a) throws InterruptedException {
    // Pre-code...
    
    // Add the lock code
    synchronized (SynchronizedExample.class) {
        / /...
    }
    
    // Post code...
}
Copy the code

When the above code is executed, the decorated code block is called a synchronous statement block, and its scope is the code block enclosed in curly brackets “{}”, and its scope is the object that called it.

In addition to locking class, we can also lock this, as shown in the following example:

public void classMethod(a) throws InterruptedException {
    // Preprocessing code...
    synchronized (this) {
        / /...
    }
    // Post processing code...
}
Copy the code

What’s the difference between this and class using synchronized? Don’t they all lock the same class?

The answer is no. There is a big difference between locking this and class. Let’s look at the differences with four examples below.

1. The locked class shares a class instance

First, we create 5 threads that call the synchronized class code on the same object:

import java.util.Date;
import java.util.concurrent.TimeUnit;

public class SynchronizedExample {

    public static void main(String[] args) {
        // Create an instance of the current class
        final SynchronizedExample example = new SynchronizedExample();
        // Create 5 threads to execute the task
        for (int i = 0; i < 5; i++) {
            new Thread(new Runnable() {
                @Override
                public void run(a) {
                    try {
                        // Synchronized class methods are invoked
                        example.classMethod();
                    } catch(InterruptedException e) { e.printStackTrace(); } } }).start(); }}/** * synchronized@throws InterruptedException
     */
    public void classMethod(a) throws InterruptedException {
        synchronized (SynchronizedExample.class) {
            System.out.println(String.format("Current execution thread :%s, execution time :%s",
                    Thread.currentThread().getName(), new Date()));
            TimeUnit.SECONDS.sleep(1); }}}Copy the code

The execution results of the above procedures are as follows:As you can see from the above results, these five threads share the same lock.

2. Create multiple instances by locking classes

Next, we create five threads that call the synchronized class code on different objects, as shown in the following example:

import java.util.Date;
import java.util.concurrent.TimeUnit;

public class SynchronizedExample {

    public static void main(String[] args) {
        // Create 5 threads to execute the task
        for (int i = 0; i < 5; i++) {
            new Thread(new Runnable() {
                @Override
                public void run(a) {
                    try {
                        // Create a class instance
                        SynchronizedExample example = new SynchronizedExample();
                        // Synchronized class methods are invoked
                        example.classMethod();
                    } catch(InterruptedException e) { e.printStackTrace(); } } }).start(); }}/** * synchronized@throws InterruptedException
     */
    public void classMethod(a) throws InterruptedException {
        synchronized (SynchronizedExample.class) {
            System.out.println(String.format("Current execution thread :%s, execution time :%s",
                    Thread.currentThread().getName(), new Date()));
            TimeUnit.SECONDS.sleep(1); }}}Copy the code

The execution results of the above procedures are as follows:As you can see from the above results, although these are different objects, they still use the same lock.

3. Lock this to share a class instance

Next, let’s create the example of synchronized with five threads calling this. First of all, we call the 5 threads of the same object lock method, sample code is as follows:

import java.util.Date;
import java.util.concurrent.TimeUnit;

public class SynchronizedExample {

    public static void main(String[] args) {
        // Create an instance of the current class
        final SynchronizedExample example = new SynchronizedExample();
        // Create 5 threads to execute the task
        for (int i = 0; i < 5; i++) {
            new Thread(new Runnable() {
                @Override
                public void run(a) {
                    try {
                        // And synchronized
                        example.thisMethod();
                    } catch(InterruptedException e) { e.printStackTrace(); } } }).start(); }}/** * synchronized@throws InterruptedException
     */
    public void thisMethod(a) throws InterruptedException {
        synchronized (this) {
            System.out.println(String.format("Current execution thread :%s, execution time :%s",
                    Thread.currentThread().getName(), new Date()));
            TimeUnit.SECONDS.sleep(1); }}}Copy the code

The execution results of the above procedures are as follows:As you can see from the above results, the threads used the same lock.

4. Lock this to create multiple class instances

In the last and most specific example, we use synchronized to have each of the five threads call the method that created the object.

import java.util.Date;
import java.util.concurrent.TimeUnit;

public class SynchronizedExample {

    public static void main(String[] args) {
        // Create 5 threads to execute the task
        for (int i = 0; i < 5; i++) {
            new Thread(new Runnable() {
                @Override
                public void run(a) {
                    try {
                        // Create (multiple) class instances
                        SynchronizedExample example = new SynchronizedExample();
                        // And synchronized
                        example.thisMethod();
                    } catch(InterruptedException e) { e.printStackTrace(); } } }).start(); }}/** * synchronized@throws InterruptedException
     */
    public void thisMethod(a) throws InterruptedException {
        synchronized (this) {
            System.out.println(String.format("Current execution thread :%s, execution time :%s",
                    Thread.currentThread().getName(), new Date()));
            TimeUnit.SECONDS.sleep(1); }}}Copy the code

The execution results of the above procedures are as follows:“Synchronized” is not the same as the synchronized “this” class, but it is the same as the synchronized “this” class.

conclusion

We can conclude from the above four examples that when we use the synchronized lock class, we use the same lock whether we share an object or create multiple objects, whereas when we use the synchronized lock class, only the same lock is used for the same object. Locking is different for different objects.

Recommended articles in this series

  1. Concurrency Lesson 1: Thread in Detail
  2. What’s the difference between user threads and daemon threads in Java?
  3. Get a deeper understanding of ThreadPool
  4. 7 ways to create a thread pool, highly recommended…
  5. How far has pooling technology reached? I was surprised to see the comparison between threads and thread pools!
  6. Thread synchronization and locking in concurrency
  7. The difference between volatile and synchronized
  8. Are lightweight locks faster than weight locks?
  9. How can terminating a thread like this lead to service downtime?
  10. 5 Solutions to SimpleDateFormat Thread Insecurity!
  11. ThreadLocal doesn’t work? Then you are useless!
  12. ThreadLocal memory overflow code demonstration and cause analysis!
  13. Semaphore confessions: I was right to use the current limiter!
  14. CountDownLatch: Don’t wave. Wait till you’re all together!
  15. CyclicBarrier: When all the drivers are ready, they can start.

Follow the public number “Java Chinese community” for more interesting and informative Java concurrent articles.