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.
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
}
}
}
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.
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