item 82 jihoon - JAVA-JIKIMI/EFFECTIVE-JAVA3 GitHub Wiki

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

μžλ°”λ…μ΄ κΈ°λ³Έ μ˜΅μ…˜μ—μ„œ μƒμ„±ν•œ API λ¬Έμ„œμ—λŠ” synchronized ν•œμ •μžκ°€ ν¬ν•¨λ˜μ§€ μ•ŠλŠ”λ‹€. λ©”μ„œλ“œ 선언에 synchronized ν•œμ •μžλ₯Ό μ„ μ–Έν• μ§€λŠ” κ΅¬ν˜„ 이슈일 뿐 API에 μ†ν•˜μ§€ μ•ŠλŠ”λ‹€. λ”°λΌμ„œ μ΄κ²ƒλ§ŒμœΌλ‘œλŠ” κ·Έ λ©”μ„œλ“œκ°€ μŠ€λ ˆλ“œ μ•ˆμ „ν•˜λ‹€κ³  λ―ΏκΈ° μ–΄λ ΅λ‹€.

μŠ€λ ˆλ“œ μ•ˆμ „μ„± μˆ˜μ€€(μ•ˆμ „μ„± 높은 μˆœμ„œλ‘œ λ‚˜μ—΄)

  • λΆˆλ³€(immutable)
    • 이 클래슀의 μΈμŠ€ν„΄μŠ€λŠ” 마치 μƒμˆ˜μ™€ κ°™μ•„ μ™ΈλΆ€ 동기화도 ν•„μš” μ—†λ‹€
    • E.g. String, Long, BigInteger
  • 무쑰건적인 μŠ€λ ˆλ“œ μ•ˆμ „(unconditionally thread-safe)
    • 이 클래슀의 μΈμŠ€ν„΄μŠ€λŠ” μˆ˜μ •λ  수 μžˆμ§€λ§Œ λ‚΄λΆ€μ—μ„œλ„ μΆ©μ‹€νžˆ λ™κΈ°ν™”ν•˜μ—¬ λ³„λ„μ˜ μ™ΈλΆ€ 동기화없이 λ™μ‹œμ— μ‚¬μš©ν•΄λ„ μ•ˆμ „
    • E.g. AtomicLong, ConcurrentHashMap
  • 쑰건뢀 μŠ€λ ˆλ“œ μ•ˆμ „(conditionally thread-safe)
    • 무쑰건적인 μŠ€λ ˆλ“œ μ•ˆμ „μ„±κ³Ό κ°™μ§€λ§Œ 일뢀 λ©”μ„œλ“œλŠ” λ™μ‹œμ— μ‚¬μš©ν•˜λ €λ©΄ μ™ΈλΆ€ 동기화가 ν•„μš”ν•©λ‹ˆλ‹€.
    • E.g. Collections.synchronized Wrapper λ©”μ„œλ“œκ°€ λ¦¬ν„΄ν•œ μ»¬λ ‰μ…˜(이 μ»¬λ ‰μ…˜λ“€μ΄ λ¦¬ν„΄ν•œ λ°˜λ³΅μžλŠ” μ™ΈλΆ€μ—μ„œ 동기화해야 ν•œλ‹€)
  • μŠ€λ ˆλ“œ μ•ˆμ „ν•˜μ§€ μ•ŠμŒ(not thread-safe)
    • 이 클래슀의 μΈμŠ€ν„΄μŠ€λŠ” μˆ˜μ •λ  수 있고, λ™μ‹œμ— μ‚¬μš©ν•˜λ €λ©΄ 각각의 λ©”μ„œλ“œ ν˜ΈμΆœμ„ ν΄λΌμ΄μ–ΈνŠΈκ°€ μ„ νƒν•œ μ™ΈλΆ€ 동기화 둜직으둜 감싸야 ν•œλ‹€.
    • E.g. ArrayList, HashMap
  • μŠ€λ ˆλ“œ μ λŒ€μ (thread-hostile)
    • μ™ΈλΆ€ λ™κΈ°ν™”λ‘œ 감싸더라도 λ©€ν‹°μŠ€λ ˆλ“œ ν™˜κ²½μ—μ„œ μ•ˆμ „ν•˜μ§€ μ•Šλ‹€.
    • μ΄λŸ¬ν•œ ν΄λž˜μŠ€λŠ” λ™μ‹œμ„±μ„ κ³ λ €ν•˜μ§€ μ•Šκ³  λ§Œλ“€λ‹€λ³΄λ©΄ μš°μ—°νžˆ λ§Œλ“€μ–΄μ§„λ‹€.

쑰건뢀 μŠ€λ ˆλ“œ μ•ˆμ „ 클래슀의 λ¬Έμ„œν™”

  • 쑰건뢀 μŠ€λ ˆλ“œ μ•ˆμ „ν•œ ν΄λž˜μŠ€λŠ” μ£Όμ˜ν•˜μ—¬ λ¬Έμ„œν™”ν•΄μ•Ό ν•œλ‹€.

    • μ–΄λ– ν•œ μˆœμ„œλ‘œ ν˜ΈμΆœν•  λ•Œ μ™ΈλΆ€ 동기화 둜직이 ν•„μš”ν•œμ§€, 그리고 κ·Έ μˆœμ„œλ‘œ ν˜ΈμΆœν•˜λ €λ©΄ μ–΄λ–€ 락을 μ–»μ–΄μ•Όλ§Œ ν•˜λŠ”μ§€ μ•Œλ €μ£Όμ–΄μ•Ό ν•œλ‹€.
    • 일반적으둜 μΈμŠ€ν„΄μŠ€ 자체λ₯Ό 락으둜 μ–»μ§€λ§Œ, μ˜ˆμ™Έλ„ μžˆλ‹€.
    // synchronizedMap이 λ°˜ν™˜ν•œ 맡의 μ½œλ ‰μ…˜ λ·°λ₯Ό μˆœνšŒν•˜λ €λ©΄, λ·°(μΈμŠ€ν„΄μŠ€ 자체)κ°€ μ•„λ‹Œ λ°˜λ“œμ‹œ κ·Έ 맡을 락으둜 μ‚¬μš©ν•΄ μˆ˜λ™μœΌλ‘œ λ™κΈ°ν™”ν•˜λΌ
    
    Map<K, V> m = Collections.synchronizedMap(new HashMap());
    Set<K> s = m.keySet();  // 동기화 블둝 밖에 μžˆμ–΄λ„ λœλ‹€.
        ...
    synchronized (m) {  // sκ°€ μ•„λ‹Œ m을 μ‚¬μš©ν•΄ 동기화해야 ν•œλ‹€.
        for (K key : s)
    	    key.f();
    }
    
    // μ΄λŒ€λ‘œ λ”°λ₯΄μ§€ μ•ŠμœΌλ©΄ λ™μž‘μ„ μ˜ˆμΈ‘ν•  수 μ—†λ‹€
  • 클래슀의 μŠ€λ ˆλ“œ μ•ˆμ „μ„±μ€ 보톡 클래슀의 λ¬Έμ„œν™” 주석에 기재

  • λ…νŠΉν•œ νŠΉμ„±μ˜ λ©”μ„œλ“œλΌλ©΄ ν•΄λ‹Ή λ©”μ„œλ“œμ˜ 주석에 기재

  • μ—΄κ±°νƒ€μž…μ€ ꡳ이 λΆˆλ³€μ΄λΌκ³  μ“Έ ν•„μš” μ—†μŒ

  • 리턴 νƒ€μž…λ§ŒμœΌλ‘œλŠ” λͺ…ν™•νžˆ μ•Œ 수 μ—†λŠ” 정적 νŒ©ν„°λ¦¬λŠ” μžμ‹ μ΄ λ¦¬ν„΄ν•˜λŠ” 객체의 μŠ€λ ˆλ“œ μ•ˆμ „μ„±μ„ λ°˜λ“œμ‹œ λ¬Έμ„œν™”ν•΄μ•Ό ν•œλ‹€(Collections.synchronizedMap이 쒋은 예)

μ™ΈλΆ€μ—μ„œ μ‚¬μš©ν•  수 μžˆλŠ” lock의 주의점

  • ν΄λž˜μŠ€κ°€ μ™ΈλΆ€μ—μ„œ μ‚¬μš©ν•  수 μžˆλŠ” lock을 μ œκ³΅ν•˜λ©΄ ν΄λΌμ΄μ–ΈνŠΈμ—μ„œ 일련의 λ©”μ„œλ“œ ν˜ΈμΆœμ„ μ›μžμ μœΌλ‘œ ν•  수 μžˆλ‹€.
  • λ‚΄λΆ€μ—μ„œ μ²˜λ¦¬ν•˜λŠ” κ³ μ„±λŠ₯ λ™μ‹œμ„± μ œμ–΄ λ©”μ»€λ‹ˆμ¦˜κ³Ό ν˜Όμš©ν•  수 μ—†κ²Œ λœλ‹€.
  • ν΄λΌμ΄μ–ΈνŠΈκ°€ 곡개된 lock 였래 μ₯κ³  놓지 μ•ŠλŠ” μ„œλΉ„μŠ€ κ±°λΆ€ 곡격(denial-of-service attack)을 μˆ˜ν–‰ν•  수 μžˆλ‹€.
    • 이 곡격을 막기 μœ„ν•΄μ„œλŠ” 곡개된 lockμ΄λ‚˜ λ§ˆμ°¬κ°€μ§€μΈ synchronized λ©”μ„œλ“œ λŒ€μ‹  λΉ„κ³΅κ°œ lock 객체λ₯Ό μ‚¬μš©ν•΄μ•Ό ν•œλ‹€.

λΉ„κ³΅κ°œ lock 객체 κ΄€μš©κ΅¬

private final Object lock = new Object();

public void someMethod() {
    synchronized(lock) {
        ...
    }
}
  • lock ν•„λ“œλ₯Ό 항상 final둜 μ„ μ–Έν•˜λΌ
    • lock 객체가 μš°μ—°νžˆλΌλ„ κ΅μ²΄λ˜λŠ” 일 예방
    • 일반적인 κ°μ‹œ lock, java.util.concurrent.locks νŒ¨ν‚€μ§€μ—μ„œ κ°€μ Έμ˜¨ lock λͺ¨λ‘ ν•΄λ‹Ή
  • λΉ„κ³΅κ°œ lock 객체 κ΄€μš©κ΅¬λŠ” 무쑰건적 μŠ€λ ˆλ“œ μ•ˆμ „ ν΄λž˜μŠ€μ—μ„œ μ‚¬μš©ν•  수 μžˆλ‹€
    • 쑰건뢀 μŠ€λ ˆλ“œ μ•ˆμ „ ν΄λž˜μŠ€μ—μ„œλŠ” νŠΉμ • 호좜 μˆœμ„œμ— ν•„μš”ν•œ 락이 무엇인지λ₯Ό ν΄λΌμ΄μ–ΈνŠΈμ—κ²Œ μ•Œλ €μ€˜μ•Ό ν•˜λ―€λ‘œ 이 κ΄€μš©κ΅¬λ₯Ό μ‚¬μš©ν•  수 μ—†λ‹€.
⚠️ **GitHub.com Fallback** ⚠️