[Java] synchronized์ Lock
Java์์ Lock์ ์ฌ์ฉํ๋ ๋ฐฉ๋ฒ๊ณผ ๊ทธ ์ข ๋ฅ์ ๋ํด ์ ๋ฆฌํด๋ณธ๋ค.
๋ฉํฐ์ค๋ ๋์ Data Race ๋ฌธ์
Lock๋ ๋ฉํฐ์ค๋ ๋ ํ๊ฒฝ์์ ๋ฐ์ํ๋ ๋ํ์ ์ธ ๋ถ์์ฉ์ธ ๋์์ฑ ์ฐ๊ธฐ, Data race ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ๊ธฐ ์ํด ์กด์ฌํ๋ค. ์ด ๋ฌธ์ ์ ๋ํด ์๋ค๋ฉด ๋ฌด์ํ๊ณ ๋์ด๊ฐ๋ ๋๋ค.

package org.example;
class SharedObject {
public int count = 0;
}
public class Main {
public static void main(String[] args) {
var shared = new SharedObject();
// ์ค๋ ๋๋ฅผ 5๊ฐ ์์ฑํด์ count๋ฅผ ์ฆ๊ฐ์ํด
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(() -> {
for (int j = 0; j < 1000; j++) {
shared.count++;
}
});
thread.start();
}
// ๋ชจ๋ ์ค๋ ๋๊ฐ ์ข
๋ฃ๋ ๋๊น์ง ๋๊ธฐ
while (Thread.activeCount() > 1) {
Thread.yield();
}
System.out.println(shared.count);
}
}
์ฝ๋๋ฅผ ๋ณด๋ฉด, ์ค๋ ๋๋ฅผ 5๊ฐ ๋์ฐ๊ณ ๊ณต์ ์์์ ๋ํด์ ๊ณ์ํด์ +1 ์ฐ์ฐ์ ๊ฐํ๊ณ ์๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
์ค๋ ๋ 5๊ฐ์์ 1000๋ฒ์ฉ ์ฆ๊ฐ ์ฐ์ฐ์ ๋๋ฆฌ๋, ์ผ๋ฐ์ ์ผ๋ก๋ ์ต์ข
๊ฒฐ๊ณผ๊ฐ์ด 5000์ด ๋ ๊ฒ์ด๋ผ๊ณ ๊ธฐ๋ํ ์ ์๋ค.
ํ์ง๋ง ์ค์ ๊ฒฐ๊ณผ๋ ๊ทธ๋ ์ง ์๋ค.
์ฌ๋ฌ๊ฐ์ ์ค๋ ๋์์ n+1 ์ฐ์ฐ์ ๊ฐํ๋๋ฐ, ๊ทธ๊ฒ ๋์์ ์ค์ฒฉ๋๋ค๋ฉด 2๊ฐ ์ด์์ ์ค๋ ๋์์ ๋์ผํ ๊ฐ์ ์ฐ๋ฉด์ ํ๋๋ฅผ ์ ์ธํ ์ค๋ ๋์ write๊ฐ ๋ฒ๋ ค์ง ์ ์๊ธฐ ๋๋ฌธ์ด๋ค.
๋ฌผ๋ก ์ด๊ฑด ์์ฃผ ๋จ์ํ ๊ฒฝ์ฐ๊ณ , ์ค์ ํ๋ก๊ทธ๋จ์์ ๋์์ฑ ๋ฌธ์ ๋ ๋ณดํต ์ข ๋ ๋ณต์กํ ํํ๋ก ๋๋ฌ๋๋ค.
์๋ฌดํผ ์ฌ๊ธฐ์ ์ค์ํ ๊ฒ์, ์ฌ๋ฌ๊ฐ์ ์ค๋ ๋์์ "๋์์ ์ฐ๋ ํ์" ์์ฒด๊ฐ ๋งค์ฐ ์ํํ๋ค๋ ๊ฒ์ด๋ค.
synchronized๋ฅผ ์ด์ฉํ Lock
Java๋ ๋๋ฌผ๊ฒ ๋๊ธฐํ์ ๋ํ ์ง์์ ์ธ์ด ์ ํ์ค๋ถํฐ ์ง์ํ๋ ์ธ์ด๋ค.
synchronized ํค์๋๋ฅผ ๋ฉ์๋์ ๋ถ์ด๋ฉด, ๊ทธ ๋ฉ์๋๋ ์๋ฒฝํ๊ฒ ๋๊ธฐํ๋๋ ๋ฉ์๋๊ฐ ๋๋ค.
๋์ผํ ๊ฐ์ฒด์ ๋ํด์ ์ ๋ฉ์๋๋ฅผ ์คํํ๋ฉด, ์ ๋ฉ์๋ ์์ฒด๋ ๋์์ ํ๋์ฉ๋ง ์ํ๋๋ ๊ฒ์ด ๋ณด์ฅ๋๋ค.
์ข ๋ ์๋ฆฌ๋ฅผ ์์ธํ๊ฒ ์ค๋ช ํ์๋ฉด, ๋ฉ์๋๊ฐ ์์๋ ๋ ์ ๊ฐ์ฒด(this)๋ฅผ ๊ธฐ์ค์ผ๋ก Mutex.lock์ ๊ฑธ๊ณ , ๋ฉ์๋๊ฐ ๋๋๋ฉด Mutex.unlock์ ๊ฑฐ๋ ๊ฒ์ด๋ค.
๊ทธ๋ ๊ฒ ๋๊ธฐํ๋ ๋ฉ์๋๋ฅผ ๋ง๋ค๊ณ ๊ทธ๊ฑธ๋ก ๋์ฒดํ๋ฉด

๊ธฐ๋ํ ๋๋ก ์ถฉ๋์ ๋ ์ด์ ๋ฐ์ํ์ง ์์ ๊ฒ์ด๋ค.
package org.example;
class SharedObject {
public int count = 0;
// synchronized ํค์๋๋ฅผ ์ฌ์ฉํ๋ฉด ๋ฉ์๋ ์ ์ฒด์ ๋ฝ์ด ๊ฑธ๋ฆผ
public synchronized void increment() {
count++;
}
}
public class Main {
public static void main(String[] args) {
var shared = new SharedObject();
// ์ค๋ ๋๋ฅผ 5๊ฐ ์์ฑํด์ count๋ฅผ ์ฆ๊ฐ์ํด
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(() -> {
for (int j = 0; j < 1000; j++) {
shared.increment();
}
});
thread.start();
}
// ๋ชจ๋ ์ค๋ ๋๊ฐ ์ข
๋ฃ๋ ๋๊น์ง ๋๊ธฐ
while (Thread.activeCount() > 1) {
Thread.yield();
}
System.out.println(shared.count);
}
}synchronized ๋ธ๋ญ์ ํตํ ๋๊ธฐํ
์ด๊ฒ๋ synchronized ๋ฉ์๋์ ๋์๋ฐฉ์์ ๊ฑฐ์ ๋์ผํ๋ค.
๊ทธ ๋ฒ์๊ฐ ๋ฉ์๋ ๋ฒ์์์ ๋ธ๋ก ๋ฒ์๋ก ์ขํ์ง ๊ฒ์ผ ๋ฟ์ด๋ค.
๋ฉ์๋๊ฐ ๊ธธ๊ณ , ๋ฝ์ ์ก์์ผํ ๋ฒ์๊ฐ ํ์ ์ ์ด๋ผ๋ฉด ๋ฉ์๋ ์ ์ฒด์ ๋ํด์ ๊ฑฐ๋ ๊ฒ์ ์ฒ๋ฆฌ๋์ ๋จ์ด๋จ๋ฆฌ๋ ์ง์ด๊ธฐ ๋๋ฌธ์, ๋ฝ์ ๊ฑธ์ด์ผํ ๋ฒ์์ ๋ํด์๋ง ๊ฑธ์ด์ฃผ๋ ๊ฒ์ด ์ข๋ค.
์ฌ์ฉ ๋ฐฉ๋ฒ์ ์ด๋ ต์ง ์๋ค.
์ด๋ฐ ๋๋์ผ๋ก lock ๋ธ๋ญ์ ์ก๊ณ ๊ทธ ์์์๋ง ๋์์ฑ ์ฐ๊ธฐ๋ฅผ ํ๋ฉด ๋๋ค.
์๊ดํธ์ ๋ค์ด๊ฐ๋ ์ธ์๊ฐ lock์ ์ก๋ ๊ธฐ์ค๊ฐ์ธ๋ฐ, ๋ณดํต this๋ฅผ ๋ฃ์ด์ ์ ๊ฐ์ฒด ์์ฒด์ ๋ํด์๋ง ๋ณด์ฅํ๋ค. ์ ์ด์ synchronized method๋ synchronized(this)๊ฐ ๋ด๋ถ ๋์์ด๋ค.
synchronized์ ๋ฌธ์
synchronized๊ฐ ๊ฐ๋จํ๊ณ ์ฌ์ฉ์ด ํธ๋ฆฌํ๊ธด ํ์ง๋ง, ๋จ์ ๋ ๋ง๋ค.
์ด๊ฑด ์ ๋ง ์์ฃผ ๋จ์ํ ์ฌ์ฉ์ฌ๋ก์์๋ง ์ธ๋งํ๊ณ , ์ต์ ํ๊ฐ ํ์ํ ์์ญ์์๋ ํ๊ณ๊ฐ ํฌ๋ค.
๊ฐ์ฅ ํฐ ๋ฌธ์ ๋ Lock์ ์ก๋ ๋ฒ์๋ฅผ ์ธ๋ฐํ๊ฒ ์กฐ์ ํ ์ ์๋ค๋ ๊ฒ์ด๋ค.
๊ทธ๋์ ํด๋น ๊ฐ์ฒด์ ๋ณ๊ฐ์ ํ๋ฆ์ ๊ฐ๋ ๋๊ธฐํ ํฌ์ธํธ๊ฐ 2๊ฐ ์ด์ ์์ ๊ฒฝ์ฐ์๋ ์ ์ฐํ๊ฒ ์ฒ๋ฆฌ๋ฅผ ํ ์๊ฐ ์๋ค.
๊ฒ๋ค๊ฐ ๋ค๋ฅธ Lock ๊ตฌํ์ฒด๊ฐ ์ ๊ณตํ๋ lock ํ์์์, ๊ณต์ ์ฑ ์ฒ๋ฆฌ, ๋๋ฒ๊น ์์ค์์ ๋ถ์กฑํ ๋ถ๋ถ์ด ๋ง๋ค.
ReentrantLock์ ํตํ ๋ช ์์ Lock
ReentrantLock์ Java์ ๋ํ์ ์ธ Lock ๊ตฌํ์ฒด ์ค ํ๋๋ค.
์ฝ๊ฒ ๋งํ๋ฉด ๊ทธ๋ฅ Mutex ๊ตฌํ์ธ๋ฐ, ๊ทธ ์ธ์๋ ์์ํ ๊ธฐ๋ฅ๋ค์ด ์กฐ๊ธ ๋ถ์ด์๋ค.
ํ๋ฒ ์ฑ๋ฅ๋น๊ต๋ฅผ ํด๋ณด๋ฉด์ ReentrantLock์ด ์ ์ ํ ๊ฒฝ์ฐ๋ฅผ ์๋ก ๋ค์ด๋ณด๊ฒ ๋ค.
์ด๋ฒ ๊ฐ์ฒด์๋ 2๊ฐ์ ๊ณต์ ๋ณ์๊ฐ ์๊ณ , ๊ฐ๊ฐ์ ์ฆ๊ฐ๋ฅผ ์ฒ๋ฆฌํ๋ ํจ์๋ฅผ ๋ง๋ค์๋ค.


๊ทธ๋ฆฌ๊ณ ์ค๋ ๋ ์๋ฉ ๋์์ ๋๋ฆฌ๋ฉด,
package org.example;
class SharedObject {
public int a_count = 0;
public int b_count = 0;
public synchronized void increment_a() {
a_count++;
}
public synchronized void increment_b() {
b_count++;
}
}
public class Main {
public static void main(String[] args) {
var shared = new SharedObject();
var start = System.currentTimeMillis();
// ์ค๋ ๋๋ฅผ 5๊ฐ ์์ฑํด์ count๋ฅผ ์ฆ๊ฐ์ํด
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(() -> {
for (int j = 0; j < 10000000; j++) {
shared.increment_a();
shared.increment_b();
}
});
thread.start();
}
// ๋ชจ๋ ์ค๋ ๋๊ฐ ์ข
๋ฃ๋ ๋๊น์ง ๋๊ธฐ
while (Thread.activeCount() > 1) {
Thread.yield();
}
var end = System.currentTimeMillis();
System.out.println("a_count: " + shared.a_count);
System.out.println("b_count: " + shared.b_count);
System.out.println("์คํ ์๊ฐ: " + (end - start) + "ms");
}
}
๋์ ์์ฒด๋ ๊ธฐ๋ํ ๋๋ก ๋ ๊ฒ์ด๋ค.
๊ทผ๋ฐ ๋ฌธ์ ๋ ์๋๋ค. synchronized๋ ๊ฐ์ฒด ์ ์ฒด๋ฅผ ์ ๊ทธ๋ ๊ฑด๋ฐ, ์ ์ฌ์ฉ ์ฌ๋ก์์๋ ๊ตณ์ด ์ ์ฒด๋ฅผ ์ ๊ธ ํ์๋ ์๋ค.
a๋ a๋๋ก ์ ๊ทธ๋ฉด ๋๊ณ , b๋ b๋๋ก ์ ๊ทธ๋ฉด ๋๋๋ฐ, a์ ์ ๊ทผํ๋๋ฐ๋ b๊น์ง ์ ๊ฐ๋ฒ๋ฆฌ๋ ๋ฌธ์ ๊ฐ ๋ฐ์ํ๋ ๊ฒ์ด๋ค.
a์ b์ ๋ํด ๋ณ๋์ Lock ์ฒ๋ฆฌ๋ฅผ ๋ํ๋ฉด ๋ถํ์ํ Lock์ผ๋ก ์ธํ ์ ์ค ์๊ฐ์ ์ค์ผ ์ ์๋ค.
๊ฐ๊ฐ์ Lock์ ๋ช
์์ ์ผ๋ก ์ถ๊ฐํ๊ณ
์ ๊ทผ ์ง์ ์ lock์ ๊ฑธ์ด์ค๋ค.
๊ทธ๋ฌ๋ฉด
package org.example;
import java.util.concurrent.locks.ReentrantLock;
class SharedObject {
public int a_count = 0;
public int b_count = 0;
public ReentrantLock a_lock = new ReentrantLock();
public ReentrantLock b_lock = new ReentrantLock();
public void increment_a() {
a_lock.lock();
a_count++;
a_lock.unlock();
}
public void increment_b() {
b_lock.lock();
b_count++;
b_lock.unlock();
}
}
public class Main {
public static void main(String[] args) {
var shared = new SharedObject();
var start = System.currentTimeMillis();
// ์ค๋ ๋๋ฅผ 5๊ฐ ์์ฑํด์ count๋ฅผ ์ฆ๊ฐ์ํด
for (int i = 0; i < 5; i++) {
Thread thread = new Thread(() -> {
for (int j = 0; j < 10000000; j++) {
shared.increment_a();
shared.increment_b();
}
});
thread.start();
}
// ๋ชจ๋ ์ค๋ ๋๊ฐ ์ข
๋ฃ๋ ๋๊น์ง ๋๊ธฐ
while (Thread.activeCount() > 1) {
Thread.yield();
}
var end = System.currentTimeMillis();
System.out.println("a_count: " + shared.a_count);
System.out.println("b_count: " + shared.b_count);
System.out.println("์คํ ์๊ฐ: " + (end - start) + "ms");
}
}
์ ์๋ 2์ด์ฏค ๊ฑธ๋ฆฌ๋๊ฒ ์ด์ 1์ด ๋ฏธ๋ง์ผ๋ก ์ฒ๋ฆฌ๋๋ ๊ฒ์ ๋ณผ ์ ์๋ค.
ReenterantLock: ๊ณต์ ์ฑ (fairness)
Lock ๊ฒฝํฉ์ด ๋งค์ฐ ์ฌํ ์ํฉ์์๋, ์ด์ด ์ข์ง ๋ชปํ๋ค๋ฉด ํน์ ์ค๋ ๋๋ง ๊ณ์ํด์ Lock์ ์ ์ ํ์ง ๋ชปํ ์ ์๋ค.
์ด๋ฐ ํ์์ ๋ถ๊ณต์ (unfair)ํ๋ค๊ณ ํ๋ค.
ReenterantLock์ ๊ณต์ ํ Lock ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค.
์์ฑ์์ true๋ฅผ ๋๊ธฐ๋ฉด ๊ณต์ ๋ชจ๋๋ก ์๋ํด์, ์ค๋ ๋๋ค์ด ๊ณต์ ํ๊ฒ Lock์ ์ ์ ํ๋๋ก ์ ๋ํ๋ค.
์๋ฅผ ๋ค๋ฉด, ๊ฐ์ฅ ์ค๋ ๊ธฐ๋ค๋ฆฐ ์ค๋ ๋์๊ฒ Lock ์ฐ์ ์์๋ฅผ ์ฃผ๋ ๊ฒ์ด๋ค.
๋จ, ๊ณต์ ์ฑ์ด ๋ฐ๋์ ๋ณด์ฅ๋๋ ๊ฒ์ ์๋๋ค. ๊ฐ์ฅ ์ค๋ ๊ธฐ๋ค๋ฆฐ ์ค๋ ๋๋ฅผ ์ ํธ(favor)ํ๋ ๊ฒ์ผ ๋ฟ์ด๋ค.
๊ทธ๋ฆฌ๊ณ ๊ณต์ ์ฑ์ ๊ณต์ง๋ก ์ฃผ์ด์ง๋๊ฒ ์๋๋ผ, ์ถ๊ฐ์ ์ธ ๋๊ธฐํ๋ ๋ก์ง์ด ๋ค์ด๊ฐ๋ ๊ฒ์ด๋ค.
๊ทธ๋์ ๊ธฐ๋ณธ ๋์๋ณด๋ค ํจ์ฌ ๋๋ ค์ง ์ ์๋ค.
ReenterantLock: ์ฌ์ง์ ๊ฐ๋ฅ
์ฌ์ค ์ด๊ฑธ ์ข์ ๋์์ธ์ด๋ผ ํ ์ ์๋์ง๋ ๋ชจ๋ฅด๊ฒ ๋๋ฐ... synchronized์ ReenterantLock์ ์ฌ์ง์
๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค.
์ด๊ฒ ๋ฌด์จ ๋ง์ด๋๋ฉด, ์ด๋ฏธ Lock์ ์ก์ ์ค๋ ๋๊ฐ Lock์ ์ค๋ณตํด์ ๋ ์ก์ ์ ์๋ค๋ ๋ง์ด๋ค.
๊ทธ๋์ ์ด๋๋ ์ ๋์ํ๋ค.
๊ทผ๋ฐ ์ด๋ฐ ์ฝ๋๋ฅผ ์ข์ ์ฝ๋๋ผ๊ณ ํ ์ ์์์ง๋ ์ ๋ชจ๋ฅด๊ฒ ๋ค.
ReentrantLock: timeout ๊ธฐ๋ฐ Lock
๊ธฐ์กด์ Lock ๊ธฐ๋ฅ๋ค์ Lock์ ์ ์ ํ ๋๊น์ง ํ์ผ์์ด ๊ธฐ๋ค๋ฆฐ๋ค.
๊ทผ๋ฐ ๊ฒฝ์ฐ์ ๋ฐ๋ผ์๋ ๋น์ฅ Lock์ ์ ์ ํ ์ ์๋ค๋ฉด ๋ค๋ฅธ ์์
์ ๋ ์ฒ๋ฆฌํ๋๋ก ๊ตฌํ์ ํ๋๊ฒ ์ฒ๋ฆฌ๋ ์ธก๋ฉด์์ ์ ๋ฆฌํ ์ํฉ์ด ์์ ์๋ ์๋ค.
tryLock์ ์ฌ์ฉํ๋ฉด Lock์ ์ก๋ค๊ฐ timeout์ด ์ง๋๋ฉด ํฌ๊ธฐํ๊ณ ๋์ค๋๋ก ํ ์ ์๋ค.
๊ทธ๋ฆฌ๊ณ Lock์ ์ก๋๋ฐ ์ฑ๊ณตํ๋ค๋ฉด tryLock์ true๋ฅผ ๋ฐํํ๋ค.
ReentrantReadWriteLock๋ฅผ ํตํ Lock
ReentrantReadWriteLock์ ๋ค๋ฅธ ์ธ์ด์ Read-Write-Mutex์ ๋๋ฑํ Lock ๊ตฌํ์ฒด๋ค.
ReentrantLock์๋ ์กฐ๊ธ ์ฑ๋ฅ์ ์ธ ๋จ์ ์ด ์๋ค.
์ฝ๊ธฐ ๋น์ค์ด ๋งค์ฐ ๋์ ๊ฒฝ์ฐ์๋ Lock์ผ๋ก ์ธํ ์ฑ๋ฅ ์์ค์ด ๊ฝค ์ปค์ง ์ ์๋ค๋ ๊ฒ์ด๋ค.
๊ทธ๋ฐ๋ฐ ์๋ค์ํผ, read์ ๋ํ ๋๊ธฐํ๋ write์ ๋นํ๋ฉด ๊ฝค ์ ๋ ดํ๋ค. ์ฝ๊ธฐ๋ฅผ ํ๋๋ฐ write ์์ค์ Lock์ ํญ์ ๊ฑธ ํ์๋ ์๋ ๊ฒ์ด๋ค.
๊ทธ๋์ ReadWriteLock์ read์ write์ ๋ํ Lock์ 2๋จ๊ณ๋ก ์ ์ดํ๋ Lock์ด๋ค. ์ด๋ฅผ ํตํด read ๋ถํ๊ฐ ๋์ ๊ฒฝ์ฐ์๋ ์ผ๋ฐ ReentrantLock๋ณด๋ค ๋์ ์ฑ๋ฅ์ ๊ธฐ๋ํ ์ ์๋ค.
๊ธฐ๋ณธ์ ์ธ ์ฌ์ฉ ์๋ฆฌ๋ ํฌ๊ฒ ๋ค๋ฅด์ง ์๋ค.
๋์
writeLock๊ณผ
readLock์ ๋ช
์์ ์ผ๋ก ๊ฑธ ์ ์๋ค.
writeLock์ ๊ฑธ๋ฉด ๋ค๋ฅธ writeLock๊ณผ readLock์ด ๋ชจ๋ ์ฐจ๋จ๋์ง๋ง, readLock์ ๋ค๋ฅธ Lock์ ์ฐจ๋จํ์ง ์๋๋ค.
์ด์ฐจํผ writeLock์ ๋ง์ด ๊ฑด๋ค๋ฉด ReentrantLock๋ง ์ฐ๋๊ฒ ๋ ๋จ์ํ๊ณ ์ฑ๋ฅ์ด ์ ๋์ฌ ์๋ ์๋ค.
StampedLock๋ฅผ ํตํ Lock
StampedLock๋ ReentrantReadWriteLock์ ์กฐ๊ธ ๋ ๋๊ด์ ์ธ ๋ฒ์ ์ด๋ค.
์ค๋ ๋์ ์ฌ์ง์
์ ํ์ฉํ์ง ์๋๋ค.
๊ทธ๋ฆฌ๊ณ write lock์ด ์กํ์๋ ์ํ๋ผ๋ read lock์ ๋์จํ๊ฒ ์ก์ ์ ์๋ค๋๊ฒ ํน์ง์ด๋ค.
์ด๊ธฐํ ๋ฐฉ๋ฒ์ ํฌ๊ฒ ๋ค๋ฅผ๊ฒ ์๊ณ
write Lock์ ์ก๋ ๊ฒ๋ ReentrantReadWriteLock์ ํฌ๊ฒ ๋ค๋ฅด์ง ์๋ค.
๋ค๋ฅธ๊ฑด Read Lock์ ์ก๋ ๋ถ๋ถ์ด๋ค.
Read Lock์ ์ก์๋๋ tryOptimisticRead์ ์ฃผ๋ก ์ฌ์ฉํ๋๋ฐ, ์ด๊ฑด write lock์ด ์กํ์๋ ๋ง๋ ์ผ๋จ ๊ฐ์ ธ์จ๋ค.
๊ทผ๋ฐ ๋น์ฐํ write๊ฐ ๋ถ์์ ํ๊ฒ ์ฒ๋ฆฌ๋ ์ํฉ์์๋ ์ ๋งคํ ๊ฐ์ด๋ ์๋ ๊ฐ์ ์ฐธ์กฐํ ์๋ ์๋ค.
์ฌ๊ธฐ์ ํต์ฌ์ lock.validate๋ฅผ ์ฌ์ฉํด์ ์คํฌํ ๊ฐ ๊ธฐ๋ฐ์ผ๋ก ๊ฒ์ฆ์ ํ ์ ์๋ ๊ฒ์ด๋ค.
๊ฒ์ฆ์ ์คํจํ๋ค๋ฉด ๊ทธ์ ์์ผ readLock์ผ๋ก Lock์ ๋๊ธฐํ๊ณ ์ต์ ๊ฐ์ ์ฒ๋ฆฌํ๊ฒ ํ๋ฉด ๋๊ณ , ๊ฒ์ฆ์ ์ฑ๊ณตํ๋ค๋ฉด ๊ทธ๋๋ก ์จ๋ ๋๋ค.
์ฐธ์กฐ
https://velog.io/@may_yun/JAVA-synchronized-VS-Reentrant-Lock-%EC%B0%A8%EC%9D%B4%EC%A0%90
https://stackoverflow.com/questions/60903107/understanding-fair-reentrantlock-in-java
https://stackoverflow.com/questions/57809112/reentrantlock-vs-reentrantreadwritelock
https://stackoverflow.com/questions/26094200/what-is-stampedlock-in-java
https://stackoverflow.com/questions/55766479/how-to-to-use-stampedlock-optimistic-locking-i-cant-understand-code-sample-fr