Virtual Thread์ ๋ํด์ ๊ณต๋ถํ๋ ์ค, Pinned Issue๋ก ์ธํด ์คํ๋ง ๋ถํธ ๋ด๋ถ ์ฝ๋์ `synchronized` ํค์๋๋ฅผ `ReentrantLock`์ผ๋ก ์์ ํ๊ณ ์์์ ์๊ฒ๋์๋ค. ํ์ง๋ง ๋ด๊ฐ ์๊ณ ์๋ ์๋ฐ ๋์์ฑ ์ ์ด ์ค ๋น๊ด์ ๋ฝ์ ๋งค์ปค๋์ฆ์ synchronized ํค์๋๊ฐ ์ ์ผํ๋ค. ์ด์ `ReentrantLock`๊ณผ ๊ฐ์ ์ถ๊ฐ์ ์ธ ๋น๊ด์ ๋ฝ ๋ฉ์ปค๋์ฆ์ ๋ํด ์์๋ดค๊ณ ๊ทธ์ ๋ํด ์ ๋ฆฌํด๋ณด๊ณ ์ ํ๋ค.
1๏ธโฃ Synchronized
Synchronized๋ ์๋ฐ์์ ๊ฐ์ฅ ๊ฐ๋จํ๊ฒ ์ฌ์ฉํ ์ ์๋ ๋์์ฑ ์ ์ด ๋ฐฉ๋ฒ์ผ๋ก ํน์ Blcok ๋๋ ๋ฉ์๋์ ๋ถ์ฌ์ ์ฌ์ฉํ ์ ์๋ค.
public class SynchronizedExample {
private int a = 0;
public synchronized void increment() {
a++;
}
public synchronized void decrement() {
a--;
}
}
์์ ๊ฐ์ด ๋ฉ์๋์ ๋ถ์ฌ์ ์ฌ์ฉํ ๊ฒฝ์ฐ ํ๋์ ๋ฉ์๋์ ํ๋์ ์ค๋ ๋๋ง ์ ๊ทผํ ์ ์์์ ์๋ฏธํ๋ค. ์ฌ๊ธฐ์ ์ฃผ์ํด์ผ ํ ์ ์ ๋ฉ์๋์ synchronized ํค์๋๋ฅผ ์ฌ์ฉํ ๊ฒฝ์ฐ ํด๋น ๋ฉ์๋๋ฅผ ํฌํจํ๊ณ ์๋ ์ธ์คํด์ค(SynchronizedExample) ๋ ๋ฒจ์ ๋ฝ์ ์ด์ฉํ๊ธฐ ๋๋ฌธ์ ํ ์ค๋ ๋๊ฐ increment ๋ฉ์๋๋ฅผ ์ฌ์ฉํ๋ ๋์ ๋ค๋ฅธ ๋ฉ์๋๋ increment ๋ฉ์๋๋ ๋ฌผ๋ก decrement ๋ฉ์๋์๋ ์ ๊ทผํ ์ ์๋ค๋ ๊ฒ์ด๋ค.
๋ํ `public static synchronized void method1()` ๊ณผ ๊ฐ์ด ์คํํฑ ๋ฉ์๋์ ๋์์ฑ ์ ์ด๋ฅผ ๊ฑธ ๊ฒฝ์ฐ ํด๋์ค ๋ ๋ฒจ์ ๋ฝ์ ๊ฑธ์ด ํด๋น ํด๋์ค์ ๋ชจ๋ ์ธ์คํด์ค์์ ์ค๋ ๋ ๋์ ์ ๊ทผ์ ์ ํํ๋ค.
public void addName(String name) {
synchronized(this) {
lastName = name;
nameCount++;
}
nameList.add(name);
}
์์ ๊ฐ์ด ํน์ Block์๋ง synchronized๋ฅผ ์ ์ฉํจ์ผ๋ก์จ ๋์์ฑ ์ ์ด์ ๋ฒ์๋ฅผ ์ค์ผ ์ ์๋ค. ์ ์ฝ๋์์ `synchronized(this)`์ `this`๋ ๊ฐ์ฅ ํํ ์ฌ์ฉ๋๋ statement๋ก `ํด๋น ํด๋์ค๋ฅผ ๋ค๋ฅธ ์ค๋ ๋๊ฐ Lockingํ๊ณ ์์ง ์๋ค๋ฉด` ์ด๋ผ๋ ์๋ฏธ๋ฅผ ๊ฐ์ง๋ค. ํด๋น Statement์ ํด๋์ค ๊ฐ์ฒด๊ฐ ์๋ ์์์ ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ์ฌ ๋ฝ์ ์ ์ฐํ๊ฒ ์ฌ์ฉํ๋๋ก ํ ์ ์๋๋ฐ, ์ด ๊ฒ์ด `ReetrantLock` ํด๋์ค์ด๋ค.
2๏ธโฃ ReentrantLock
class X {
private final ReentrantLock lock = new ReentrantLock();
// ...
public void m() {
lock.lock(); // block until condition holds
try {
// ... method body
} finally {
lock.unlock()
}
}
}
ํน์ Block์ ์ง์ ํ์ฌ ๋์์ฑ ์ ์ด๋ฅผ ํ๊ณ ์ ํ ๋ synchronized ํค์๋๋ฅผ ๋์ ํด์ ReentrantLock ๊ฐ์ฒด๋ฅผ ์ฌ์ฉํ ์ ์๋ค. ์ฌ๊ธฐ๊น์ง๋ง ๋ค์์ ๋๋ synchronized๋ฅผ ReentrantLock์ผ๋ก ๋์ฒดํ๋ ์ด์ ๋ฅผ ์ฐพ๊ธฐ ์ด๋ ค์ธ ๊ฒ์ด๋ค.
ํ์ง๋ง ์ค๋ ๋๊ฐ ๋ฝ์ ์ ์ ํ๊ณ ์์ ๊ฒฝ์ฐ ๋ค๋ฅธ ์ค๋ ๋๋ค์ ๋ฝ์ Release ํ ๋๊น์ง ๋ฌดํ์ ๋๊ธฐํด์ผํ๋ synchronized ํค์๋์๋ ๋ฌ๋ฆฌ, ReentrantLock ๊ฐ์ฒด๋ ๋ฉ์๋๋ฅผ ํตํด ์๋์ ๊ฐ์ ๋ค์ํ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค.
- Lock์ ์ํ๋ฅผ ํ์ธํ ์ ์๋ค.
- ์ฝ๋๊ฐ ๋จ์ผ ๋ธ๋ก ํํ๋ฅผ ๋์ด์๋ ๊ฒฝ์ฐ ์ฌ์ฉ ๊ฐ๋ฅ ํ๋ค.
- ํ์ ์์์ ์ง์ ํ ์ ์๋ค.
- Condition์ ์ ์ฉํด์ ๋๊ธฐ ์ค์ธ ์ฐ๋ ๋๋ฅผ ์ ๋ณ์ ์ผ๋ก ๊นจ์ธ ์ ์๋ค.
- lock ํ๋์ ์ํด waiting pool์ ์๋ ์ฐ๋ ๋์๊ฒ ์ธํฐ๋ฝํธ๋ฅผ ๊ฑธ ์ ์๋ค.
โ ReentrantLock์ ์ฃผ์ ๋ฉ์๋
- lock() : Lock์ ์ป์ด์จ๋ค.
- unlock() : Lock์ ํด์ ํ๋ค.
- tryLock() : ์ผ์ ์๊ฐ์ ๊ธฐ๋ค๋ฆฌ๋๊ฐ ์๋๋ฉด ์ง๊ธ ์ฆ์ ์ํ๋ฅผ ํ์ธํ๊ณ true, false๋ฅผ return ํ๋ค. true์ธ๊ฒฝ์ฐ Lock์ ์ป๋๋ค.
- isHeldByCurrentThread() : ํ์ฌ Thread๊ฐ Lock์ ์ป์๋๊ฐ?
- hasQueuedThreads() : ํด๋น ๊ฐ์ฒด์ Lock์ ์ป๊ธฐ์ํด ๊ธฐ๋ค๋ฆฌ๋ Threads๊ฐ ์๋๊ฐ?
- getOwner() : ์ง๊ธ Lock์ ๊ฐ๊ณ ์๋ Thread๋ฅผ Return ํ๋ค.
Condition
synchronized๋ ์ค๋ ๋์ ์ข ๋ฅ๋ฅผ ๊ตฌ๋ถํ์ง ์๊ณ ๊ณต์ ๊ฐ์ฒด์ waiting pool์ ๊ฐ์ด ๋๊ธฐ์์ผ ์ค๋ ๋๋ฅผ ํน์ ํ ์ ์์์ง๋ง,
ReentrantLock๊ณผ Condition์ ์ฌ์ฉํ๋ฉด ์ค๋ ๋์ ์ข ๋ฅ์ ๋ฐ๋ผ ๊ตฌ๋ถ๋ waiting pool์์ ๋ฐ๋ก ๊ธฐ๋ค๋ฆฌ๋๋ก ํ์ฌ ์ ๋ณ์ ์ธ ํต์ง๋ฅผ ๊ฐ๋ฅํ๊ฒ ํ๋ค.
private ReentrantLock lock = new ReentrantLock();
// Object.wait(), Object.notify()์ ๋ฌ๋ฆฌ ์ฌ๋ฌ ๊ฐ์ ๋๊ธฐ์ด์ ์์ฑํ ์ ์๋ค.
private Condition forTask1 = lock.newCondition();
private Condition forTask2 = lock.newCondition();
ReentrantReadWriteLock
static Runnable addCount(String threadName){
return
() -> IntStream
.range(0, 20000)
.forEach(i -> {
try {
if (writeLock.tryLock(1, TimeUnit.SECONDS)){
System.out.println(threadName + count++);
} else {
System.out.println(threadName + "failed to acquire, count = " + count);
}
} catch (InterruptedException e ) {
} finally {
writeLock.unlock();
}
});
}
}
์ถ๊ฐ์ ์ผ๋ก ์๋ฐ๋ `ReentrantReadWriteLock` ํด๋์ค๋ฅผ ์ ๊ณตํ๋ค. ํด๋น ํด๋์ค๋ ์ฝ๊ธฐ ์์ ์ด ์ฃผ๋ก ์ผ์ด๋๋ ์ฝ๋ ๋ธ๋ญ์์ ์ฌ์ฉ๋๋ค. ํด๋น ํด๋์ค๋ ๋์์ ์ฌ๋ฌ ์ค๋ ๋๊ฐ ์ ๊ทผ ๊ฐ๋ฅํ `readLock`๊ณผ ํ๋์ ์ค๋ ๋๋ง ์ ๊ทผ ๊ฐ๋ฅํ `writeLock`์ ์ ๊ณตํ๋ค. ์๋์ ๊ฐ์ด `writeLock.tryLock()`๋ ๋ฝ ํญ๋์ ์๋ํ๊ณ ์ฑ๊ณต ์ฌ๋ถ์ ๋ฐ๋ผ true, false๋ฅผ ๋ฐํํ๋ค. ๋ํ ํด๋น ๋ฉ์๋๋ (time, timeUnit)๋ฅผ ๋์ ํจ์ผ๋ก์จ ์ผ์ ์๊ฐ๋์ ๋ฝ ํญ๋์ ์ํด ๋๊ธฐํ๋ ๊ธฐ๋ฅ์ ์ ๊ณตํ๋ค.
3๏ธโฃ Semaphore
์ธ๋งํฌ์ด๋ ์์์ ์ฌ๋ฌ ๊ฐ์ ์ค๋ ๋๊ฐ ์ ๊ทผํ๋ ๊ฒ์ ์ ์ดํ๋ ์ญํ ์ ํ๋ค. ์์ synchronized์ ReentrantLock์ ํ๋์ ์์์ ํ๋์ ์ค๋ ๋๋ง ์ ๊ทผํ๋ ๊ฒ์ ํ์ฉํ๊ธฐ ๋๋ฌธ์ ์ฃผ๋ก ๋ฉ์๋ ๋ด์ ํน์ ์ฝ๋ ๋ธ๋ญ์ ๋์์ฑ ์ ์ด๋ฅผ ์ํด ์ฌ์ฉ๋๋ ๋ฐ๋ฉด Semaphore๋ ThreadPool ๊ด๋ฆฌ, DBCP ๊ด๋ฆฌ ๋ฑ์ ์ฌ์ฉ๋๋ค.
Sema
- Semaphoreโ(int permits) : permits ๊ฐฏ์ ๋งํผ ์ธ๋งํฌ์ด์ Pool์ด ์ฌ์ฉ๋๋ค๊ณ ํ์
- acquireโ(int permits) : permits ๊ฐฏ์ ๋งํผ ์ธ๋งํฌ์ด์ Pool์ด ์ฌ์ฉ๋๋ค๊ณ ํ์ํ๋ค. ์์ผ๋ฉด ํ๋
- availablePermits() : ์ฌ์ฉ๊ฐ๋ฅํ Permits ๊ฐฏ์
- drainPermits() : ํ ๋ชจ๋ Permits์ ์ทจ์ํ๊ณ Availables ์ํ๋ก ๋ณํ ์ํจ๋ค
- reducePermitsโ(int reduction) : permit ๊ฐฏ์๋ฅผ ์ค์ธ๋ค
- tryAcquireโ(int permits, long timeout, TimeUnit unit) : ์ผ์ ์๊ฐ ๋๋ ์ผ์ permit ๊ฐฏ์๋ฅผ ๊ธฐ๋ค๋ ธ๋ค๊ฐ ์คํจ ํ๋ฉด false ์ฒ๋ฆฌํ๋ค . true๋๋ฉด acquire(int permits)๊ณผ ๊ฐ์ ํจ๊ณผ๋ฅผ ๋ธ๋ค.
- releaseโ(int permits) :์ฌ์ฉ๋Permit์ ๋ฐํํ๋ค.
โ๏ธ ๊ฒฐ๋ก
์์ ๊ฐ์ด Lock์ ๊ฑฐ๋ ์ฌ๋ฌ ๋ฐฉ๋ฒ๋ค์ด ์กด์ฌํ์ง๋ง ๊ทผ๋ณธ์ ์ผ๋ก ํน์ Resource๋ฅผ Lockingํ๋ค๊ณ ํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ๋ฌธ์ ๋ ํด๊ฒฐ๋์ง ์๋๋ค.
- ์ฌ๋ฌ ์ค๋ ๋๊ฐ ํ๋์ Resource๋ฅผ Lockingํ๋ฉด ์ค๋ ๋๊ฐ ๋์ด๋ ์๋ก ์๋๊ฐ ๋๋ ค์ง๋ค.
- Dead Lock์ด ๋ฐ์ํ ๊ฒฝ์ฐ ํด๊ฒฐ์ด ์ด๋ ต๊ณ , ๋ฐ์ ๊ฐ๋ฅ์ฑ๋ ๋๊ธฐ ๋๋ฌธ์ ๊ฐ๋ฐ์ด ๋ณต์กํด ์ง๋ค.
๊ทธ๋ ๊ธฐ ๋๋ฌธ์ ๊ฐ์ฅ ์ข์ ๋ฐฉ๋ฒ์ ๊ณต์ ๋๋ Resource๊ฐ Locking ๋์ง ์๊ฒ ํ๋ ๊ฒ์ด๋ค. ์ด๋ฅผ ์ํด ์๋ฐ์์๋ Atomic ํด๋์ค๋ฅผ ์ ๊ณตํ๋ค. ๋ค์ ๊ธ์์๋ AtomicX์ ์๋ฐ์ ๋์์ฑ ์ ์ด ์๋ฆฌ์ ๋ํด ๋ค๋ค๋ณด๊ณ ์ํ๋ค.