JAVA

[Java] ์ž๋ฐ” ๋™์‹œ์„ฑ ์ œ์–ด ๋ฐฉ๋ฒ•

YeopJu 2024. 8. 4. 23:13
๋ฐ˜์‘ํ˜•

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์™€ ์ž๋ฐ”์˜ ๋™์‹œ์„ฑ ์ œ์–ด ์›๋ฆฌ์— ๋Œ€ํ•ด ๋‹ค๋ค„๋ณด๊ณ ์žํ•œ๋‹ค.

๋ฐ˜์‘ํ˜•