About synchronized and Reentrant Lock (Java & Kotlin implementation example)

What is synchronized

In the first place, Java provides a modifier called synchronized to make operations related to specific objects thread-safe. For example, give as follows.

Data.java



public class Data {
    int x = 0;
    int y = 0;

    public synchronized void inc() { // synchronized method
        x += 1;
        y += 1;
    }

    public void dec() {
        synchronized (this) { // synchronized statement
            x -= 1;
            y -= 1;
        }
    }
}

If you define a method with synchronized, the thread that calls the method takes a lock on this instance (in this case the Data instance). Once the lock is acquired, other threads will block any processing that requires a lock on this instance until the lock is released. There are two ways to use it: synchronized method and synchronized statement.

The above inc () method and dec () method are methods that add/subtract 1 to x and y, respectively, but if they are not synchronized by synchronized, the values ​​of ** x and y will differ depending on the calls from multiple threads. ** A condition can occur.

This is a pretty important factor for Java programmers, but Kotlin doesn't provide a synchronized modifier. Instead, it provides @Synchronized annotations and synchronized inline functions.

[https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.jvm/-synchronized/:title]

Data.kt



class Data(var x: Int, var y: Int) {
    @Synchronized
    fun inc() {
        x += 1
        y += 1
    }
    
    fun dec() {
        synchronized(this) {
            x -= 1
            y -= 1
        }
    }
}

Now you have written code that is almost equivalent to Java and Kotlin.

About Reentrant Lock

ReentrantLock is a locking mechanism for parallel processing contained in java.util.concurrent. You can achieve synchronization similar to synchronized.

When using it, create an instance of ReentrantLock and acquire and release it with lock () and unlock (). If another thread has acquired the lock, it will be blocked by lock (). It is recommended to use try-finally for JavaDoc so that unlock () is not done.

Data.java


public class Data {
    int x = 0;
    int y = 0;
    Lock lock = ReentrantLock(true);

    public void inc() {
        lock.lock();
        try {
            x += 1;
            y += 1;
        } finally {
            lock.unlock()
        }
    }
}

In the case of Kotlin, you can write smarter by using the withLock inline function as follows. WithLock acquires the lock before entering the block and releases the lock when exiting.

Data.kt


class Data(var x: Int, var y: Int) {
    val lock = ReentrantLock(true)
    fun inc() {
        lock.withLock {
            x += 1
            y += 1
        }
    }
}

merit and demerit

Which implementation is better to synchronize after all? You may want to read the following to find out. https://www.ibm.com/developerworks/java/library/j-jtp10264/ https://stackoverflow.com/questions/11821801/why-use-a-reentrantlock-if-one-can-use-synchronizedthis

When should I use ReentrantLock? The answer to the question is as follows.

The answer is pretty simple -- use it when you actually need something it provides that synchronized doesn't, like timed lock waits, interruptible lock waits, non-block-structured locks, multiple condition variables, or lock polling.

If you add a Japanese translation without permission, it will be as follows.

The answer is quite simple, when you need to be unable to synchronized. For example, wait with timeout, wait that can be interrupted, how to write a lock that is not a block structure, multiple conditional variables, check the lock status, etc.

In response to the debate over which one to choose, synchronized locks provide minimal functionality for synchronization between threads, which is sufficient, or ReentrantLock because you want to take advantage of more flexible synchronization capabilities. It is also possible to use.

Afterword

When I was studying in a fairly old book, I barely touched on the java.util.concurrent API, and I ended up revisiting the modern implementation. However, it seems that J2SE 5.0 was released on September 30, 2004, and I think that the Java area has accumulated a considerable amount of know-how regarding java.util.concurrent.

Recommended Posts

About synchronized and Reentrant Lock (Java & Kotlin implementation example)
About synchronized and Reentrant Lock
[Java] About String and StringBuilder
About Java Packages and imports
Differences between "beginner" Java and Kotlin
About fastqc of Biocontainers and Java
Encoding and Decoding example in Java
[Java beginner] About abstraction and interface
Java 15 implementation and VS Code preferences
BloomFilter description and implementation sample (JAVA)
About Java primitive types and reference types
This and that about Base64 (Java)
About the classification and concept of Immutable / Mutable / Const / Variable of Java and Kotlin.
Conversion between Kotlin nullable and Java Optional
Relationship between kotlin and java access modifiers
About Spring Dependency Injection using Java, Kotlin
Java implementation to create and solve mazes
[For beginners] Difference between Java and Kotlin
[About JDBC that connects Java and SQL]
About Kotlin
Kotlin functions and lambdas to send to Java developers
Java switch statement and break, Kotlin when expression ...
[ev3 × Java] Interface, implementation and inheritance (event handling)
About Java data types (especially primitive types) and literals
PostgreSQL Pub / Sub functionality and Java client implementation
Java and Swift comparison (3) Class implementation / Class inheritance / Class design
PrintObserver "Observer Design Pattern: Description and Implementation Example"