Item 82. Thread Safety Level

μŠ€λ ˆλ“œ μ•ˆμ „μ„± μˆ˜μ€€μ„ λ¬Έμ„œν™”ν•˜λΌ

λ©”μ„œλ“œμ— synchronized ν•œμ •μžκ°€ μžˆλ‹€κ³  ν•΄μ„œ μŠ€λ ˆλ“œ μ•ˆμ •μ„±μ΄ ν™•μ‹€ν•œ 것이 μ•„λ‹ˆλ‹€. λ‹¨μˆœ synchronized 유무둜 μŠ€λ ˆλ“œ μ•ˆμ •μ„±μ„ νŒλ‹¨ν•  수 μ—†μœΌλ©°, μŠ€λ ˆλ“œ μ•ˆμ •μ„±μ—λ„ μˆ˜μ€€μ΄ λ‚˜λ‰˜κΈ° λ•Œλ¬Έμ— κ·Έ μˆ˜μ€€μ— λŒ€ν•΄ μš°μ„  잘 μ•Œμ•„μ•Ό ν•œλ‹€. μ•„λž˜λŠ” 일반적인 κ²½μš°μ— λŒ€ν•΄ μŠ€λ ˆλ“œ μ•ˆμ •μ„± μˆ˜μ€€μ΄ 높은 순으둜 λ‚˜μ—΄ν•œ 것이닀.

  1. λΆˆλ³€(immutable)

    • μƒμˆ˜μ™€ κ°™μ•„μ„œ μ™ΈλΆ€ 동기화가 ν•„μš” μ—†μŒ

    • String, Long, BigInteger λ“± 쑴재

  2. 무쑰건적 μŠ€λ ˆλ“œ μ•ˆμ „(unconditionally thread-safe)

    • μˆ˜μ •λ  수 μžˆμœΌλ‚˜, λ‚΄λΆ€μ—μ„œ 동기화λ₯Ό μ²˜λ¦¬ν•˜μ—¬ μ™ΈλΆ€μ—μ„œ λ³„λ„μ˜ 동기화가 ν•„μš” μ—†μŒ

    • AtomicLong, ConcurrentHashMap λ“± 쑴재

  3. 쑰건뢀 μŠ€λ ˆλ“œ μ•ˆμ „(conditionally thread-safe)

    • 일뢀 λ©”μ„œλ“œλŠ” μ™ΈλΆ€μ—μ„œ 동기화가 ν•„μš” μ—†μœΌλ‚˜, 일뢀 λ©”μ„œλ“œλŠ” μ™ΈλΆ€μ—μ„œ 동기화가 ν•„μš”ν•¨

    • Collections.synchronized 래퍼 λ©”μ„œλ“œκ°€ λ°˜ν™˜ν•œ μ»¬λ ‰μ…˜λ“€μ΄ ν•΄λ‹Ή

  4. μŠ€λ ˆλ“œ μ•ˆμ „ν•˜μ§€ μ•ŠμŒ(not thread-safe)

    • μΈμŠ€ν„΄μŠ€κ°€ μˆ˜μ •λ  수 있으며, λ™μ‹œμ— μ‚¬μš©ν•˜κΈ° μœ„ν•΄μ„  λ©”μ„œλ“œ ν˜ΈμΆœμ„ μ™ΈλΆ€ 동기화 λ§€μ»€λ‹ˆμ¦˜μœΌλ‘œ 감싸야 함

    • ArrayList, HashMap λ“± κΈ°λ³Έ μ»¬λ ‰μ…˜λ“€μ΄ ν•΄λ‹Ή

  5. μŠ€λ ˆλ“œ μ λŒ€μ (thread-hostile)

    • μ™ΈλΆ€μ—μ„œ 동기화λ₯Ό μ²˜λ¦¬ν•΄λ„ μŠ€λ ˆλ“œ μ•ˆμ •μ„±μ„ 보μž₯ν•  수 μ—†μŒ

    • λ™μ‹œμ„±μ„ κ³ λ €ν•˜μ§€ μ•Šκ³  μ„€κ³„λœ ν΄λž˜μŠ€λ“€μ΄ ν•΄λ‹Ήν•˜λ©°, 일반적으둜 κ³ μ³μ Έμ„œ 재배포 λ˜κ±°λ‚˜ deprecated λ˜λŠ” κ²½μš°κ°€ 많음

APIλ₯Ό μž‘μ„±ν•˜κ³  μ•ˆμ „ν•˜κ²Œ μ‚¬μš©ν•˜κΈ° μœ„ν•΄μ„ , μœ„μ˜ μŠ€λ ˆλ“œ μ•ˆμ •μ„± μˆ˜μ€€μ„ λͺ…μ‹œν•΄μ£ΌλŠ” 것이 μ’‹λ‹€. 특히 μ•„λž˜μ˜ κ²½μš°μ—” μ£Όμ˜ν•˜κ±°λ‚˜ λ°˜λ“œμ‹œ λ¬Έμ„œν™”ν•΄μ£ΌλŠ” 것이 μ’‹λ‹€.

  • 쑰건뢀 μŠ€λ ˆλ“œ μ•ˆμ „ 클래슀인 경우 μ–΄λ–€ μˆœμ„œλ‘œ ν˜ΈμΆœν•  λ•Œ μ™ΈλΆ€ 동기화가 ν•„μš”ν•œμ§€, κ·Έ μˆœμ„œλ‘œ ν˜ΈμΆœν•˜κΈ° μœ„ν•΄ μ–΄λ–€ 락을 μ‚¬μš©ν•΄μ•Ό ν•˜λŠ”μ§€ λͺ…μ‹œν•΄μ•Ό 함

  • 정적 νŒ©ν„°λ¦¬μΈ 경우 μžμ‹ μ΄ λ°˜ν™˜ν•˜λŠ” 객체의 μŠ€λ ˆλ“œ μ•ˆμ •μ„± μˆ˜μ€€μ„ λ¬Έμ„œν™”ν•΄μ•Ό 함

μ™ΈλΆ€ Lock 제곡과 μ„œλΉ„μŠ€ κ±°λΆ€ 곡격

ν΄λž˜μŠ€μ—μ„œ μ™ΈλΆ€μ—μ„œ μ‚¬μš©ν•  수 μžˆλŠ” 락을 μ œκ³΅ν•˜λ©΄ ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ μ—¬λŸ¬ 개의 λ©”μ„œλ“œ ν˜ΈμΆœμ„ μ›μžμ μœΌλ‘œ μˆ˜ν–‰ν•  수 있게 λœλ‹€. ν•˜μ§€λ§Œ 이 μœ μ—°μ„±μœΌλ‘œ 인해, λ‚΄λΆ€μ—μ„œ μ²˜λ¦¬ν•˜λŠ” λ™μ‹œμ„± μ œμ–΄ λ§€μ»€λ‹ˆμ¦˜μ„ ν˜Όμš©ν•  수 μ—†λ‹€λŠ” 점과 μ„œλΉ„μŠ€ κ±°λΆ€ 곡격에 λ…ΈμΆœλ  수 μžˆλ‹€λŠ” 점을 μ£Όμ˜ν•΄μ•Ό ν•œλ‹€. (** μ„œλΉ„μŠ€ κ±°λΆ€ 곡격: ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ 락을 νšλ“ν•œ μ±„λ‘œ 놓지 μ•ŠλŠ” 것)

synchornized λ©”μ„œλ“œλŠ” ν•΄λ‹Ή μΈμŠ€ν„΄μŠ€λ‚˜ ν΄λž˜μŠ€μ— λŒ€ν•΄ 락을 걸게 λ˜λŠ”λ°, κ·Έλ ‡κ²Œ 되면 ν΄λΌμ΄μ–ΈνŠΈκ°€ 락을 νšλ“ν•œ μ±„λ‘œ 놓지 μ•Šμ„ 수 μžˆλ‹€. λ•Œλ¬Έμ— μ„œλΉ„μŠ€ κ±°λΆ€ 곡격을 막기 μœ„ν•΄μ„  synchornized λ©”μ„œλ“œ λŒ€μ‹  λΉ„κ³΅κ°œ 락 객체λ₯Ό μ‚¬μš©ν•΄μ•Ό ν•œλ‹€.

class Counter {

    private final Object lock = new Object(); // λΉ„κ³΅κ°œ 락 객체
    private int count;

    public Counter() {
        this.count = 0;
    }

    public void increment() {
        synchronized (lock) {
            count++;
        }
    }

    public void decrement() {
        synchronized (lock) {
            count--;
        }
    }

    public int getCount() {
        synchronized (lock) {
            return count;
        }
    }
}

μœ„μ™€ 같이 λΉ„κ³΅κ°œ 락 객체λ₯Ό private + final둜 μ„ μ–Έν•˜λ©΄ ν΄λΌμ΄μ–ΈνŠΈκ°€ 객체 동기화에 κ΄€μ—¬ν•  수 μ—†κ²Œ λ˜λ©΄μ„œ μ„œλΉ„μŠ€ κ±°λΆ€ 곡격을 막을 수 μžˆλ‹€. λΉ„κ³΅κ°œ 락 객체 κ΄€μš©κ΅¬λŠ” 무쑰건적 μŠ€λ ˆλ“œ μ•ˆμ „ ν΄λž˜μŠ€μ—λ§Œ μ‚¬μš©ν•  수 있으며, 쑰건뢀 μŠ€λ ˆλ“œ μ•ˆμ „ ν΄λž˜μ„œμ—μ„  ν•„μš”ν•œ 락이 무엇인지 ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ μ•Œλ €μ€˜μ•Ό ν•˜λ―€λ‘œ μ‚¬μš©ν•  수 μ—†λ‹€.

Last updated