synchronized in Java

In Java, the synchronized keyword is a built-in synchronization mechanism used to control concurrent access to shared resources by multiple threads. When a thread accesses a method or code block modified by synchronized, it will automatically acquire the lock and release the lock when exiting, thereby ensuring that only one thread can execute the code at the same time, ensuring the safety of the operation. Atomicity and visibility.

The following are further explanations and examples of the two main uses of the synchronized keyword:

Synchronization method

Using the synchronized keyword at the method level can make the entire method a synchronized method. When a thread accesses a synchronized method on an object, it will hold the object’s lock until the method returns. Any synchronized methods by other threads that want to access the object will block.

]

public synchronized void syncMethod() {
    // synchronization code
}

Synchronized code block

You can also choose to use synchronized to synchronize a specific block of code rather than the entire method. In this way, only the thread executing the code block needs to acquire the lock, which can reduce waiting time and improve the concurrency performance of the program.

public void someMethod() {
    synchronized (this) {
        // Synchronized code block
    }
}

In this example, this is the locked object. You can also lock other objects to control the granularity of synchronization:

private final Object lock = new Object();

public void someMethod() {
    synchronized (lock) {
        // Synchronized code block
    }
}

Here, we use a special object named lock as the lock.

Now let’s look at a specific example of using the synchronized keyword:

public class SynchronizedExample {
    private int count = 0;

    // Synchronization method modified using synchronized keyword
    public synchronized void incrementCount() {
        count + + ;
    }

    public void doWork() {
        Thread thread1 = new Thread(new Runnable() {
            public void run() {
                for (int i = 0; i < 10000; i + + ) {
                    incrementCount();
                }
            }
        });

        Thread thread2 = new Thread(new Runnable() {
            public void run() {
                for (int i = 0; i < 10000; i + + ) {
                    incrementCount();
                }
            }
        });

        thread1.start();
        thread2.start();

        // Wait for both threads to finish executing
        try {
            thread1.join();
            thread2.join();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        System.out.println("Count is: " + count);
    }

    public static void main(String[] args) {
        SynchronizedExample example = new SynchronizedExample();
        example.doWork();
    }
}

Running result:

In this example, we have a count variable and an incrementCount() method, which is used to increment the value of count. We modified this method using the synchronized keyword so that only one thread can execute this method at any time.
We then created two threads, each trying to execute the incrementCount() method 10,000 times. Since the incrementCount() method is synchronous, the two threads cannot execute this method at the same time. While one thread is executing this method, the other thread must wait.
Finally, we wait for both threads to finish executing, and then print out the value of count. Since we used the synchronized keyword, the final value of count should be 20,000, because we executed the incrementCount() method a total of 20,000 times.
This is a concrete example of using the synchronized keyword, which shows how to use the synchronized keyword in Java to protect data integrity and consistency.

More Java examples of the synchronized keyword to show its usage in different situations.

1. Synchronized static method

When you synchronize a static method, the Class object of the class is locked, not the instance object. This means that these synchronized static methods cannot be accessed at the same time, even from different instances.

public class SynchronizedStaticExample {
    private static int staticCount = 0;
    
    public static synchronized void incrementStaticCount() {
        staticCount + + ;
    }
}

2. Synchronize different objects of a class

In this example, we will synchronize code blocks of different objects, using Class objects as locks.

public class SynchronizedBlockOnClass {
    private int count = 0;
    
    public void incrementCount() {
        synchronized(SynchronizedBlockOnClass.class) {
            count + + ;
        }
    }
}

In the above example, the lock is the Class object of the SynchronizedBlockOnClass.class class, not an instance of the class. This means that even different instances of the class will not enter the synchronized code block at the same time.

3. Synchronized collection

When manipulating collections, you can ensure thread safety by synchronizing code blocks.

import java.util.ArrayList;
import java.util.List;

public class SynchronizedCollectionExample {
    private List<Integer> synchronizedList = new ArrayList<>();
    
    public void addValue(int value) {
        synchronized(synchronizedList) {
            synchronizedList.add(value);
        }
    }
}

In this example, we use synchronizedList as the lock object when adding elements to ArrayList.

4. Synchronize different methods

Sometimes, you may need to synchronize different methods of the same class so that when one thread accesses one synchronized method, other threads cannot access another synchronized method.

public class SynchronizedDifferentMethods {
    public synchronized void syncMethod1() {
        // Do something
    }

    public synchronized void syncMethod2() {
        // Do something else
    }
}

In the above code, if thread A is executing syncMethod1, thread B will not be able to execute syncMethod2 because both methods are synchronized on the same object instance.

5. Synchronous recursive call

You need to be careful when using synchronized in recursive calls, because recursive calls may cause the thread to hold the lock for too long, thus reducing concurrency performance.

public class SynchronizedRecursion {
    private int count = 0;

    public synchronized void recursivePrint(int value) {
        count + + ;
        if (value <= 0) {
            return;
        }
        System.out.println("Recursion count: " + count + ", value: " + value);
        recursivePrint(value - 1);
    }
}

In this example, the lock is reentrant even for recursive calls, meaning the same thread can acquire the same lock multiple times.

The synchronized keyword is one of the basic ways to achieve thread synchronization in Java. It provides a simple and direct mechanism to prevent concurrency problems such as data competition and memory inconsistency. When designing multi-threaded programs, rational use of synchronized is the key to ensuring thread safety.

The knowledge points of the article match the official knowledge files, and you can further learn related knowledge. Algorithm skill tree Home page Overview 57182 people are learning the system