λ² μ–΄_
TechBear
λ² μ–΄_
전체 방문자
였늘
μ–΄μ œ
  • λΆ„λ₯˜ 전체보기 (336)
    • Spring (33)
      • κ°œλ… (13)
      • Security (5)
      • μ‹€μŠ΅ (1)
      • ν† λΉ„ μŠ€ν”„λ§ (11)
    • JPA (6)
    • ν”„λ‘œμ νŠΈ 기둝 (24)
    • DB (13)
    • JAVA (18)
    • μ•Œκ³ λ¦¬μ¦˜ (50)
      • μœ ν˜•μ •λ¦¬ (8)
      • Baekjoon (21)
      • LeetCode (18)
    • λ””μžμΈνŒ¨ν„΄ (0)
    • κ°œλ°œμ„œμ  (79)
      • Effective Java (78)
      • 객체지ν–₯의 사싀과 μ˜€ν•΄ (1)
    • 독후감 (4)
    • λ³΄μ•ˆ (2)
    • 운영체제(OS) (53)
      • 곡룑책 (53)
    • 컴퓨터 λ„€νŠΈμ›Œν¬ (28)
      • 컴퓨터 λ„€νŠΈμ›Œν¬ ν•˜ν–₯식 μ ‘κ·Ό (23)
    • 자료ꡬ쑰 (1)
    • DevOps (2)
    • μ•± 개발 (20)
      • μ•ˆλ“œλ‘œμ΄λ“œ μŠ€νŠœλ””μ˜€ (20)

λΈ”λ‘œκ·Έ 메뉴

    곡지사항

    인기 κΈ€

    νƒœκ·Έ

    • μ΄νŽ™ν‹°λΈŒμžλ°”
    • 운영체제
    • Spring
    • μŠ€ν”„λ§μ‹œνλ¦¬ν‹°
    • μ•Œκ³ λ¦¬μ¦˜
    • μžλ°”
    • μžλ°”8
    • ν† λΉ„μŠ€ν”„λ§
    • dfs
    • λ°μ΄ν„°λ² μ΄μŠ€
    • BFS
    • λ°±μ€€
    • ν•¨μˆ˜ν˜•μΈν„°νŽ˜μ΄μŠ€
    • μŠ€λ ˆλ“œ
    • leetcode
    • jpa
    • μ½”λ“œμ—…
    • java
    • μŠ€ν”„λ§
    • C++

    졜근 λŒ“κΈ€

    졜근 κΈ€

    ν‹°μŠ€ν† λ¦¬

    hELLO Β· Designed By μ •μƒμš°.
    λ² μ–΄_

    TechBear

    JAVA

    [Java] μ“°λ ˆλ“œμ˜ 동기화

    2023. 7. 14. 17:23

    πŸ” μ“°λ ˆλ“œμ˜ 동기화

    λ©€ν‹°μ“°λ ˆλ“œ ν”„λ‘œμ„ΈμŠ€μ˜ 경우 같은 μžμ›μ„ μ—¬λŸ¬ μ“°λ ˆλ“œμ—μ„œ κ³΅μœ ν•˜μ—¬ μ‚¬μš©ν•˜κΈ° λ•Œλ¬Έμ—, μ˜ˆμƒμΉ˜ λͺ»ν•œ κ²°κ³Όλ₯Ό 얻을 μˆ˜λ„ μžˆλ‹€.

    예λ₯Ό λ“€μ–΄ λˆμ„ μΈμΆœν•˜λŠ” 과정을 두 개의 μ“°λ ˆλ“œ μž‘μ—…μœΌλ‘œ μƒκ°ν•΄λ³΄μž. ν˜„μž¬ 3000원이 톡μž₯ μž”κ³ μ— 있고, μ“°λ ˆλ“œ AλŠ” 3000원 μΈμΆœμ„ μš”μ²­ν•œλ‹€. μ΄λ•Œ, μ“°λ ˆλ“œ B도 1000원을 인좜 μš”μ²­ν•œλ‹€. 이 κ²½μš°μ— μ“°λ ˆλ“œ Aκ°€ deposit -= money λ₯Ό μ‹€ν–‰ν•˜κΈ° 전에 μ“°λ ˆλ“œ Bκ°€ deposit >= money ꡬ문을 μ‹€ν–‰ν•œλ‹€λ©΄ deposit이 λ§ˆμ΄λ„ˆμŠ€κ°€ 될 것이닀. 

    public class BankAccount {
        private int deposit;
        public void withdraw(int money) {
        	if(deposit >= money) {
                deposit -= money;
                System.out.println(deposit);
            } else {
                System.out.println("λˆμ„ μΈμΆœν•  수 μ—†μŠ΅λ‹ˆλ‹€.");
            }
        }
    }

    μ΄λŸ¬ν•œ 일을 막기 μœ„ν•΄ ν•œ μ“°λ ˆλ“œκ°€ νŠΉμ • μž‘μ—…μ„ 끝마치기 μ „κΉŒμ§€ λ‹€λ₯Έ μ“°λ ˆλ“œμ˜ μž‘μ—… 싀행을 관리할 ν•„μš”κ°€ μžˆλ‹€. 이λ₯Ό μœ„ν•΄ μž„κ³„ μ˜μ—­(critical section)κ³Ό 락(lock)μ΄λΌλŠ” κ°œλ…μ΄ λ„μž…λ˜μ—ˆλ‹€.

    πŸ—οΈ μž„κ³„ μ˜μ—­κ³Ό 락

    곡유 데이터λ₯Ό μ‚¬μš©ν•˜λŠ” μ½”λ“œ μ˜μ—­μ„ μž„κ³„ μ˜μ—­μœΌλ‘œ μ§€μ •ν•˜κ³ , 곡유 데이터가 κ°€μ§€κ³  μžˆλŠ” 락을 νšλ“ν•œ μ“°λ ˆλ“œλ§Œ 이 μž„κ³„ μ˜μ—­μ— μ§„μž…ν•  수 있게 λ§Œλ“¬μœΌλ‘œμ¨ μœ„μ—μ„œ λ°œμƒν•œ 문제λ₯Ό ν•΄κ²°ν•  수 μžˆλ‹€. 이처럼 ν•œ μ“°λ ˆλ“œκ°€ μ§„ν–‰ 쀑인 μž‘μ—…μ— λ‹€λ₯Έ μ“°λ ˆλ“œκ°€ μ ‘κ·Όν•˜μ§€ λͺ»ν•˜λ„둝 λ§‰λŠ” 것을 'μ“°λ ˆλ“œ 동기화(synchronization)'라고 ν•œλ‹€.

     

    πŸ” μžλ°”μ˜ μ“°λ ˆλ“œ 동기화

    πŸ—οΈ synchronizedλ₯Ό μ΄μš©ν•œ 동기화

      μžλ°”μ—μ„œ 동기화λ₯Ό κ°€μž₯ μ‰½κ²Œ 달성할 수 μžˆλŠ” 방법은 synchronizedλ₯Ό μ΄μš©ν•˜λŠ” 것이닀. synchronizedλŠ” μž„κ³„ μ˜μ—­μ˜ λ²”μœ„μ— 따라 μ„±λŠ₯에 크게 μ’Œμ§€μš°μ§€ 되기 λ•Œλ¬Έμ— μ΅œλŒ€ν•œ 적은 μž„κ³„ μ˜μ—­μ„ μ„€μ •ν•˜λŠ” 것이 μ€‘μš”ν•˜λ‹€. 

    public class BankAccount {
        private int deposit;
        public synchronized void withdraw(int money) { // λ©”μ†Œλ“œμ— synchronizedλ₯Ό μ„ μ–Έ
        	if(deposit >= money) {
                deposit -= money;
                System.out.println(deposit);
            } else {
                System.out.println("λˆμ„ μΈμΆœν•  수 μ—†μŠ΅λ‹ˆλ‹€.");
            }
        }
    }

     

    πŸ—οΈ wait()κ³Ό notify()

    μž„κ³„ μ˜μ—­μ€ 락을 νšλ“ν•˜μ§€ λͺ»ν•œ μ“°λ ˆλ“œλŠ” μ ‘κ·Όν•  수 μ—†λ‹€. λ”°λΌμ„œ 락을 νšλ“ν•˜μ—¬ μž‘μ—…μ„ μ‹€ν–‰ν•˜κ³  μžˆλŠ” μ“°λ ˆλ“œμ˜ μž‘μ—…μ΄ 였래 κ±Έλ¦°λ‹€λ©΄ λ‹€λ₯Έ μ“°λ ˆλ“œλŠ” λͺ¨λ‘ ν•΄λ‹Ή 락을 νšλ“ν•˜κΈ° μœ„ν•΄ κΈ°λ‹€λ €μ•Ό ν•œλ‹€. μ΄λŸ¬ν•œ 상황을 κ°œμ„ ν•˜κΈ° μœ„ν•΄ wait()κ³Ό notify()λ₯Ό μ‚¬μš©ν•  수 μžˆλ‹€. 

     

    λ™κΈ°ν™”λœ μž„κ³„ μ˜μ—­μ˜ μ½”λ“œλ₯Ό μˆ˜ν–‰ν•˜λ‹€κ°€ μž‘μ—…μ„ 더 이상 μ§„ν–‰ν•  수 μ—†λ‹€λ©΄, wait()을 ν˜ΈμΆœν•˜μ—¬ μ“°λ ˆλ“œ Aκ°€ 락을 λ°˜λ‚©ν•˜κ³  κΈ°λ‹€λ¦¬κ²Œ λ§Œλ“ λ‹€. 그러면 μ“°λ ˆλ“œ Bκ°€ 락을 νšλ“ν•˜μ—¬ μž‘μ—…μ„ μˆ˜ν–‰ν•  수 μžˆλ‹€. λ‚˜μ€‘μ— μž‘μ—…μ„ μ§„ν–‰ν•  수 μžˆλŠ” 상황이 되면 notify()λ₯Ό ν˜ΈμΆœν•΄μ„œ, μ“°λ ˆλ“œ Aκ°€ λ‹€μ‹œ μž‘μ—…μ„ ν•  수 μžˆλ„λ‘ ν•œλ‹€. 

    void wait();                        // notify(), notifyAll()이 호좜될 λ•Œ κΉŒμ§€ κΈ°λ‹€λ¦°λ‹€.
    void wait(long timeout);            // μ§€μ •λœ μ‹œκ°„λ™μ•ˆ κΈ°λ‹€λ¦°λ‹€.
    void wait(long timeout, int nanos);
    void notify();
    void notifyAll();
    class Message {
        private String content;
        private boolean empty = true;
        
        public synchronized String read() {
            while (empty) {
                try {
                    wait(); // λŒ€κΈ° μƒνƒœλ‘œ μ „ν™˜
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            
            empty = true;
            notifyAll(); // λŒ€κΈ° 쀑인 μŠ€λ ˆλ“œλ₯Ό 깨움
            
            return content;
        }
        
        public synchronized void write(String message) {
            while (!empty) {
                try {
                    wait(); // λŒ€κΈ° μƒνƒœλ‘œ μ „ν™˜
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
            
            empty = false;
            this.content = message;
            notifyAll(); // λŒ€κΈ° 쀑인 μŠ€λ ˆλ“œλ₯Ό 깨움
        }
    }
    
    public class WaitNotifyExample {
        public static void main(String[] args) {
            Message message = new Message();
            
            // μ½λŠ” μŠ€λ ˆλ“œ
            Thread readerThread = new Thread(() -> {
                String receivedMessage = message.read();
                System.out.println("Received: " + receivedMessage);
            });
            
            // μ“°λŠ” μŠ€λ ˆλ“œ
            Thread writerThread = new Thread(() -> {
                String messageToSend = "Hello World!";
                message.write(messageToSend);
                System.out.println("Sent: " + messageToSend);
            });
            
            // μŠ€λ ˆλ“œ μ‹€ν–‰
            readerThread.start();
            writerThread.start();
        }
    }

    λ§Œμ•½ μ—¬κΈ°μ„œ μ“°λŠ” μŠ€λ ˆλ“œκ°€ μ—¬λŸ¬κ°œλΌλ©΄ waiting poolμ—λŠ” μ½λŠ” μ“°λ ˆλ“œμ™€ μ“°λŠ” μ“°λ ˆλ“œκ°€ 같이 μ‘΄μž¬ν•˜κ²Œ λœλ‹€. μ—¬κΈ°μ„œ notify()λ₯Ό ν˜ΈμΆœν•˜κ²Œ JVM은 랜덀으둜 ν•˜λ‚˜μ˜ μ“°λ ˆλ“œλ₯Ό μ„ νƒν•΄μ„œ μ‹€ν–‰ν•œλ‹€. λ§Œμ•½ 계속 μ½λŠ” μ“°λ ˆλ“œλ§Œ 선택이 λœλ‹€λ©΄ μ“°λŠ” μ“°λ ˆλ“œλŠ” μ˜€λž«λ™μ•ˆ κΈ°λ‹€λ¦¬κ²Œ 될 수 μžˆλ‹€. 이런 ν˜„μƒμ„ κΈ°μ•„(starvation)이라고 ν•œλ‹€.

     

    이런 κΈ°μ•„ ν˜„μƒμ„ 막기 μœ„ν•΄ notifyAll()을 ν˜ΈμΆœν•  수 μžˆμ§€λ§Œ, μ“°λŠ” μ“°λ ˆλ“œμ™€ μ½λŠ” μ“°λ ˆλ“œ λͺ¨λ‘ 톡지λ₯Ό λ°›κΈ° λ•Œλ¬Έμ— 락을 μ–»κΈ° μœ„ν•œ κ²½μŸμ„ ν•˜κ²Œ λœλ‹€. 이λ₯Ό '경쟁 μƒνƒœ(race condition)'라고 ν•œλ‹€. 이λ₯Ό ν•΄κ²°ν•˜κΈ° μœ„ν•΄μ„œλŠ” μ“°λŠ” μ“°λ ˆλ“œμ™€ μ½λŠ” μ“°λ ˆλ“œλ₯Ό κ΅¬λ³„ν•΄μ„œ 톡지해야 ν•œλ‹€. 이λ₯Ό μœ„ν•΄ Lockκ³Ό Condition을 μ΄μš©ν•  수 μžˆλ‹€.

     

    πŸ—οΈ Lockκ³Ό Condition을 μ΄μš©ν•œ 동기화

       java.util.concurrent.locks νŒ¨ν‚€μ§€κ°€ μ œκ³΅ν•˜λŠ” lock ν΄λž˜μŠ€λ“€μ„ μ΄μš©ν•˜λ©΄ synchronizedλ₯Ό μ‚¬μš©ν–ˆμ„ λ•Œ 보닀 더 μœ μ—°ν•œ 동기화λ₯Ό ν•  수 μžˆλ‹€. 

    [Lock Interface]

       μ“°λ ˆλ“œκ°€ λͺ…μ‹œμ μœΌλ‘œ 락을 νšλ“ν•˜κ³  ν•΄μ œν•  수 μžˆλŠ” λ©”μ„œλ“œλ₯Ό μ œκ³΅ν•œλ‹€. 

    // 락을 νšλ“ν•œλ‹€. νšλ“ν•  수 μ—†λŠ” 경우 μ“°λ ˆλ“œλŠ” λΈ”λ‘λœλ‹€.
    void lock()
    
    // 락을 ν•΄μ œν•œλ‹€. μ˜ˆμ™Έκ°€ λ°œμƒν•΄λ„ 락이 ν•΄μ œλ  수 μžˆλ„λ‘ finally λΈ”λ‘μ—μ„œ ν˜ΈμΆœλ˜μ–΄μ•Ό ν•œλ‹€. 
    void unlock()
    
    // 락 νšλ“μ„ μ‹œλ„ν•œλ‹€. λ§Œμ•½ λ‹€λ₯Έ μŠ€λ ˆλ“œμ— μ˜ν•΄ ν˜„μž¬ 락이 μ†Œμœ λ˜κ³  있으면
    // trueλ₯Ό λ°˜ν™˜ν•˜κ³  κ·Έλ ‡μ§€ μ•ŠμœΌλ©΄ falseλ₯Ό λ°˜ν™˜ν•œλ‹€.
    boolean tryLock()
    boolean tryLock(long time, TimeUnit unit)
    
    // 락과 ν•¨κ»˜ μ‚¬μš©ν•  수 μžˆλŠ” Condition 객체λ₯Ό λ°˜ν™˜ν•œλ‹€. 
    Condition newCondition()

     

    [ReentrantLock]

        ReentratLockμ—λŠ” 두 개의 μƒμ„±μžκ°€ 있으며, νŒŒλΌλ―Έν„°λ‘œ trueλ₯Ό λ„˜κΈ°κ²Œ 되면 였래 κΈ°λ‹€λ¦° μ“°λ ˆλ“œκ°€ lock을 νšλ“ ν•  수 있게 ν•œλ‹€. ν•˜μ§€λ§Œ, κ³΅μ •ν•˜κ²Œ μ²˜λ¦¬ν•˜κΈ° μœ„ν•΄ μ–΄λ–€ μ“°λ ˆλ“œκ°€ κ°€μž₯ 였래 κΈ°λ‹€λ ΈλŠ”μ§€ ν™•μΈν•˜λŠ” 과정을 거치기 λ•Œλ¬Έμ— μ„±λŠ₯은 λ–¨μ–΄μ§„λ‹€.

    ReentrantLock()
    ReentrantLock(boolean fair)
    public class SharedObject {
        //...
        ReentrantLock lock = new ReentrantLock();
        int counter = 0;
    
        public void perform() {
            lock.lock();
            try {
                // Critical section here
                count++;
            } finally {
                lock.unlock();
            }
        }
        //...
    }

    lock()은 lock을 얻을 λ•ŒκΉŒμ§€ μ“°λ ˆλ“œλ₯Ό λΈ”λ½μ‹œν‚€κΈ° λ•Œλ¬Έμ— μ„±λŠ₯에 λ¬Έμ œκ°€ 생길 수 μžˆλ‹€. λ”°λΌμ„œ 응닡성이 μ€‘μš”ν•œ 경우, tryLock()을 μ΄μš©ν•΄μ„œ μ§€μ •μ‹œκ°„ λ™μ•ˆ lock을 μ–»μ§€ λͺ»ν•˜λ©΄ λ‹€μ‹œ μž‘μ—…μ„ μ‹œλ„ν•  것인지 μ‚¬μš©μžκ°€ κ²°μ •ν•˜κ²Œ ν•˜λŠ” 것이 μ’‹λ‹€. 

    public void performTryLock(){
        //...
        boolean isLockAcquired = lock.tryLock(1, TimeUnit.SECONDS);
        
        if(isLockAcquired) {
            try {
                //Critical section here
            } finally {
                lock.unlock();
            }
        } else {
        	System.out.println("μ›ν•˜μ‹œλ©΄ λ‹€μ‹œ μ‹œλ„ν•΄μ£Όμ„Έμš”");
        }
    }
     

    [ReentrantReadWriteLock]

       μ½κΈ°μ—λŠ” 곡유적이고, μ“°κΈ°μ—λŠ” 배타적인 lock을 μ œκ³΅ν•œλ‹€. 더 μžμ„Ένžˆ λ§ν•˜λ©΄ 읽기 μ“°λ ˆλ“œκ°€ μž„κ³„ μ˜μ—­μ— μžˆλŠ” 경우 읽기 μ „μš© μ“°λ ˆλ“œλŠ” μ œν•œ μ—†λŠ” 락을 μ–»κ²Œ λœλ‹€. ν•˜μ§€λ§Œ μ“°κΈ°λ₯Ό ν•˜λŠ” κ²½μš°μ—λŠ” μ“°κΈ° μ“°λ ˆλ“œ ν•˜λ‚˜λ§Œ 락을 κ°€μ§ˆ 수 μžˆλ‹€. 

    public class ReadWriteMap<K, V> {
        private final Map<K, V> map = new HashMap<>();
        private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
    
        public void put(K key, V value) {
            lock.writeLock().lock();
            try {
                // μ“°κΈ° μž‘μ—… μˆ˜ν–‰
                map.put(key, value);
            } finally {
                lock.writeLock().unlock();
            }
        }
    
        public V get(K key) {
            lock.readLock().lock();
            try {
                // 읽기 μž‘μ—… μˆ˜ν–‰
                return map.get(key);
            } finally {
                lock.readLock().unlock();
            }
        }
    }

     

    [StampedLock]

       lock을 κ±Έκ±°λ‚˜ ν•΄μ§€ν•  λ•Œ μŠ€νƒ¬ν”„(long νƒ€μž…μ˜ μ •μˆ˜κ°’)λ₯Ό μ‚¬μš©ν•˜λ©°, 읽기와 μ“°κΈ°λ₯Ό μœ„ν•œ μž κΈˆμ™Έμ— 낙관적 읽기 잠금(optimisitc reading lock)을 μ œκ³΅ν•œλ‹€. 낙관적 읽기 μž κΈˆμ—μ„œλŠ” 읽기 잠금이 κ±Έλ €μžˆμ„ λ•Œ, μ“°κΈ° 잠금 μš”μ²­μ΄ λ“€μ–΄μ˜€λ©΄ 읽기 μž κΈˆμ„ κΈ°λ‹€λ¦¬λŠ” 것이 μ•„λ‹ˆλΌ 읽기 μž κΈˆμ„ λ°€μ–΄λ‚Έλ‹€. 

    public class StampedLockExample {
        private final StampedLock lock = new StampedLock();
        private double x;
        private double y;
    
        public void move(double deltaX, double deltaY) {
            long stamp = lock.writeLock();
            try {
                x += deltaX;
                y += deltaY;
            } finally {
                lock.unlockWrite(stamp);
            }
        }
    
        public double distanceFromOrigin() {
            long stamp = lock.tryOptimisticRead();
            double currentX = x;
            double currentY = y;
            if (!lock.validate(stamp)) {
                stamp = lock.readLock();
                try {
                    currentX = x;
                    currentY = y;
                } finally {
                    lock.unlockRead(stamp);
                }
            }
            return Math.sqrt(currentX * currentX + currentY * currentY);
        }
    }

    move() λ©”μ„œλ“œλŠ” μ“°κΈ° μž κΈˆμ„ νšλ“ν•˜μ—¬ μ’Œν‘œλ₯Ό μˆ˜μ •ν•˜κ³ , distanceFromOrigin() λ©”μ„œλ“œλŠ” μ΅œμ ν™”λœ 읽기 μž κΈˆμ„ μ‹œλ„ν•˜μ—¬ μ’Œν‘œλ₯Ό μ½λŠ”λ‹€. validate()λŠ” μŠ€νƒ¬ν”„λ₯Ό 인수둜 λ°›μœΌλ©°, ν•΄λ‹Ή μŠ€νƒ¬ν”„κ°€ μœ μš©ν•œμ§€ ν™•μΈν•œλ‹€. μœ νš¨μ„± κ²€μ‚¬λŠ” 데이터에 λŒ€ν•œ μ“°κΈ° μž‘μ—…μ΄ λ°œμƒν–ˆλŠ”μ§€ μ—¬λΆ€λ₯Ό ν™•μΈν•˜μ—¬ μˆ˜ν–‰λœλ‹€. λ§Œμ•½ falseλ₯Ό λ°˜ν™˜ν•˜λ©΄ 데이터에 λŒ€ν•œ μ“°κΈ° μž‘μ—…μ΄ λ°œμƒν•œ κ²ƒμœΌλ‘œ λ‹€μ‹œ 읽기 μž‘μ—…μ„ μˆ˜ν–‰ν•œλ‹€.

     

    [Condition]

       Condition은 이미 μƒμ„±λœ lockμœΌλ‘œλΆ€ν„° newCondition()을 ν˜ΈμΆœν•΄μ„œ 생성할 수 있으며 λΆ„λ¦¬λœ waiting pool을 μ‚¬μš©ν•  수 μžˆλ„λ‘ 도와쀀닀. 

    private ReentrantLock lock = new ReentrantLock();
    private Condition readLock = lock.newCondition();
    private Condition writeLock = lock.newCondition();

    wait() & notify() λŒ€μ‹  Conditionμ—μ„œλŠ” await() & signal()을 μ‚¬μš©ν•œλ‹€. 

    public class ConditionExample {
        private final Lock lock = new ReentrantLock();
        private final Condition condition = lock.newCondition();
        private boolean conditionMet = false;
    
        public void doSomething() {
            lock.lock();
            try {
                while (!conditionMet) {
                    condition.await();
                }
                // 쑰건이 좩쑱됐을 λ•Œ μˆ˜ν–‰ν•  μž‘μ—…
            } catch (InterruptedException e) {
                // μΈν„°λŸ½νŠΈ μ˜ˆμ™Έ 처리
            } finally {
                lock.unlock();
            }
        }
    
        public void notifyCondition() {
            lock.lock();
            try {
                conditionMet = true;
                condition.signal();
            } finally {
                lock.unlock();
            }
        }
    }

     

    μ €μž‘μžν‘œμ‹œ λΉ„μ˜λ¦¬ λ³€κ²½κΈˆμ§€ (μƒˆμ°½μ—΄λ¦Ό)
      'JAVA' μΉ΄ν…Œκ³ λ¦¬μ˜ λ‹€λ₯Έ κΈ€
      • [Java] λžŒλ‹€μ™€ 슀트림
      • [Java] Volatile ν‚€μ›Œλ“œ
      • [Java] μ“°λ ˆλ“œ μ™„λ²½ 정리
      • [Java] Thread vs Runnable
      λ² μ–΄_
      λ² μ–΄_
      Today I learned | 문제λ₯Ό ν•΄κ²°ν•˜λŠ” 개발자

      ν‹°μŠ€ν† λ¦¬νˆ΄λ°”