Skip to content

Latest commit

Β 

History

History
89 lines (69 loc) Β· 5.08 KB

item79.md

File metadata and controls

89 lines (69 loc) Β· 5.08 KB

κ³Όλ„ν•œ λ™κΈ°ν™”λŠ” ν”Όν•˜λΌ.

응닡 λΆˆκ°€μ™€ μ•ˆμ „ μ‹€νŒ¨λ₯Ό ν”Όν•˜λ €λ©΄ 동기화 λ©”μ„œλ“œλ‚˜ 동기화 λ“€λŸ­ μ•ˆμ—μ„œλŠ” μ œμ–΄λ₯Ό μ ˆλŒ€λ‘œ ν΄λΌμ΄μ–ΈνŠΈμ— μ–‘λ„ν•˜λ©΄ μ•ˆλœλ‹€ !

  • μ œμ–΄λ₯Ό ν΄λΌμ΄μ–ΈνŠΈμ—κ²Œ 양도 ?
    • μž¬μ •μ˜ κ°€λŠ₯ν•œ λ©”μ„œλ“œλ₯Ό ν˜ΈμΆœν•˜λŠ” ν–‰μœ„
    • ν΄λΌμ΄μ–ΈνŠΈκ°€ λ„˜κ²¨μ€€ ν•¨μˆ˜κ°μ²΄λ₯Ό ν˜ΈμΆœν•˜λŠ” ν–‰μœ„

μ΄λ ‡κ²Œ μ™ΈλΆ€μ—μ„œ 온 λ©”μ„œλ“œλ“€μ„ 외계인 λ©”μ„œλ“œ 라고 ν•˜λ©°, 이 외계인 λ©”μ„œλ“œλ“€μ€ 무슨 짓을 ν•  지 μ˜ˆμΈ‘ν•  수 μ—†κ³ , μ˜ˆμ™Έλ‚˜ κ΅μ°©μƒνƒœ, 데이터λ₯Ό 훼손할 수 μžˆλ‹€.

μ˜ˆμ‹œ μ½”λ“œ.

  • (같은 νŒ¨ν‚€μ§€μ˜ ObservableSet 을 보자.) 이 ν΄λž˜μŠ€λŠ” μ˜΅μ €λ²„ 클래슀이고, ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€ 리슀트λ₯Ό κ³΅μœ μžμ›μœΌλ‘œ μ‚¬μš©ν•˜λ©°, ꡬ독/해지/μ•ŒλžŒμ—μ„œ 동기화λ₯Ό μ§„ν–‰ν•˜κ³  μžˆλ‹€.
  • (같은 νŒ¨ν‚€μ§€μ˜ ObserverUser 을 보자.) μ—¬κΈ°μ„œλŠ” ν•¨μˆ˜ν˜• μΈν„°νŽ˜μ΄μŠ€λ₯Ό λ„£κ³ , μ‚¬μš©ν•˜λŠ”λ° 1~99 κΉŒμ§€ 좜λ ₯ν•˜λŠ” λ£¨ν”„λ¬Έμ—μ„œ 23μ—μ„œ μ˜΅μ €λ²„μ˜ ꡬ독을 ν•΄μ œν•˜κ³ μžˆλ‹€.

이 μ‚¬μš©μ˜ κ²°κ³ΌλŠ” 23μ—μ„œ ConcurrentModificationException 이닀.
λ‹€μŒμ€ 23 μ—μ„œ add λ₯Ό ν•˜λ©΄ μ‹€ν–‰λ˜λŠ” λ©”μ„œλ“œλ₯Ό μˆœμ„œλŒ€λ‘œ 적은 것이닀.

   @Override
   public boolean add(E e) {
       boolean added = super.add(e);
       if (added) notifyElementAdded(e);
       return added;
   }

   private void notifyElementAdded(E element) {
       synchronized (observers) {
           for (SetObserver<E> observer : observers) {
               observer.added(this, element);
           }
       }
   }

   public boolean removeObserver(SetObserver<E> observer) {
       synchronized (observers) {
           return observers.remove(observer);
       }
   }
  • λ‘λ²ˆμ§Έ λ©”μ„œλ“œμ—μ„œ 보면 added λ©”μ„œλ“œκ°€ observers λ₯Ό μˆœνšŒν•˜λ‹€κ°€, removeObserver λ₯Ό μ‹€ν–‰ν•˜κ³ , removeObserver λŠ” observers 의 μ›μ†Œλ₯Ό μ‚­μ œν•œλ‹€.
  • 동기화 λΈ”λŸ­μ—μ„œ μ™ΈλΆ€μ˜ λ©”μ„œλ“œλ₯Ό μ‚¬μš©ν•œκ²ƒμ΄λ‹€.
  • 이 λΆ€λΆ„μ—μ„œ synchronized 의 동기화 λΈ”λŸ­μ„ μˆ˜μ •ν•˜λ € ν–ˆκΈ°μ— μ—λŸ¬κ°€ λ°œμƒν•œλ‹€.

λ‹€λ₯Έ 예

  • (같은 νŒ¨ν‚€μ§€μ˜ ObserverUserExecutor 을 보자.) ExecutorService λ₯Ό μ΄μš©ν•˜μ—¬ μŠ€λ ˆλ“œν’€μ˜ μŠ€λ ˆλ“œμ—κ²Œ μž‘μ—…μ„ 맑겼닀.
  • 이 κ²½μš°μ—λŠ” μ˜ˆμ™ΈλŠ” λ‚˜μ§€ μ•Šμ§€λ§Œ, κ΅μ°©μƒνƒœμ— 빠진닀.
  • λ°±κ·ΈλΌμš΄λ“œ μŠ€λ ˆλ“œκ°€ s.removeObserver λ₯Ό ν˜ΈμΆœν•˜λ©΄, κ΄€μ°°μžλ₯Ό 잠그렀 μ‹œλ„ν•œλ‹€.
  • ν•˜μ§€λ§Œ 이미 메인 μŠ€λ ˆλ“œκ°€ 락을 μ₯κ³  있기 λ•Œλ¬Έμ— 락을 얻을 수 μ—†λ‹€.
  • λ™μ‹œμ— 메인 μŠ€λ ˆλ“œ λ°±κ·ΈλΌμš΄λ“œ μŠ€λ ˆλ“œκ°€ κ΄€μ°°μžλ₯Ό μ œκ±°ν•˜κΈ°λ₯Ό 기닀리고 μžˆμœΌλ―€λ‘œ κ΅μ°©μƒνƒœμ— 빠진닀.

λΆˆλ³€μ‹μ΄ κΊ μ§€λŠ” 경우

  • μœ„μ˜ 두 μ˜ˆλŠ” μ‹€νŒ¨ν•˜κΈ΄ ν•˜μ§€λ§Œ, 객체의 μƒνƒœκ°€ μœ μ§€λœ μƒνƒœμ΄λ‹€.

  • λ§Œμ•½ λΆˆλ³€μ‹μ΄ 꺠진 μƒνƒœλΌλ©΄?

  • μžλ°” μ–Έμ–΄λŠ” μž¬μ§„μž…μ„ ν—ˆμš©ν•œλ‹€.

    • μž¬μ§„μž… : 락의 νšλ“μ΄ 호좜 λ‹¨μœ„κ°€ μ•„λ‹Œ μŠ€λ ˆλ“œ λ‹¨μœ„λ‘œ μΌμ–΄λ‚˜κΈ° 떄문에, 이미 락을 νšλ“ν•œ μŠ€λ ˆλ“œλŠ” 같은 락을 μ–»κΈ° μœ„ν•΄ λŒ€κΈ°ν•  ν•„μš” μ—†λ‹€.
    • μžλ°”μ˜ synchronized 블둝은 μž¬μ§„μž…μ΄ ν—ˆμš©λœλ‹€. ν•œ μ“°λ ˆλ“œκ°€ synchronized 블둝에 μ§„μž…ν•˜λ©° λͺ¨λ‹ˆν„° 객체의 락을 νšλ“ν•˜λ©΄, μ“°λ ˆλ“œλŠ” μžμ‹ μ΄ νšλ“ν•œ λͺ¨λ‹ˆν„° 객체에 λŒ€ν•œ λ‹€λ₯Έ synchronized λΈ”λ‘μœΌλ‘œλ„ μ§„μž…ν•  수 μžˆλ‹€.
  • 락이 재 ꡬ싀을 ν•˜μ§€ λͺ»ν•˜κΈ°μ—, κ΅μ°©μƒνƒœμ˜ 데이터λ₯Ό μ•ˆμ „ μ‹€νŒ¨ (데이터 훼손) 으둜 μ΄μ–΄μ§ˆ 수 μžˆλ‹€.


μœ„ 두 문제λ₯Ό ν•΄κ²°ν•˜λŠ” 방법

  • notify λ©”μ„œλ“œμ˜ 동기화가 λ¬Έμ œλ‹€.
    • 첫번째 μ˜ˆμ‹œμ—μ„œλŠ”, notify λ©”μ„œλ“œμ˜ λ™κΈ°ν™”λœ 리슀트λ₯Ό 순회 도쀑 μˆ˜μ •μ„ ν•˜λ € ν•΄μ„œ μΌμ–΄λ‚œ 문제.
    • λ‘λ²ˆμ¨° μ˜ˆμ‹œμ—μ„œλŠ”, notify λ©”μ„œλ“œμ˜ 동기화 λΈ”λŸ­μ΄ 메인 λ©”μ„œλ“œμ˜ 락 떄문에 락을 얻을 수 μ—†μŒ. (같은 객체의 락을 μ–»μœΌλ €ν•¨)
  • λ”°λΌμ„œ notify 의 순회(외계인 λ©”μ„œλ“œμ˜ 호좜)λ₯Ό λ°–μœΌλ‘œ λΉΌλ©΄ 문제λ₯Ό ν•΄κ²°ν•  수 μžˆλ‹€.
    • 동기화 μ˜μ—­ λ°–μ—μ„œ ν˜ΈμΆœλ˜λŠ” 외계인 λ©”μ„œλ“œλ₯Ό μ—΄λ¦° 호좜 이라 ν•œλ‹€.
  • λ˜λŠ” 이 상황에 맞게 μ„€κ³„λœ CopyOnWriteArrayList λ₯Ό μ‚¬μš©ν•˜λ©΄, 동기화 없이 문제λ₯Ό ν•΄κ²°ν•  수 μžˆλ‹€.

κΈ°λ³Έ κ·œμΉ™

  • 동기화 μ˜μ—­μ—μ„œλŠ” κ°€λŠ₯ν•œ 적은 일을 ν•΄μ•Όν•œλ‹€.
  • 1 락을 μ–»κ³ , 2 곡유 데이터λ₯Ό κ²€μ‚¬ν•˜κ³ , 3 ν•„μš”ν•˜λ©΄ μˆ˜μ •ν•˜κ³ , 4 락을 λ†“λŠ”λ‹€.

κ°€λ³€ 클래슀λ₯Ό μž‘μ„±ν•˜λŠ” μš”λ Ή

  1. 동기화λ₯Ό μ „ν˜€ ν•˜μ§€ 말고, κ·Έ 클래슀λ₯Ό μ‚¬μš©ν•˜λŠ” ν΄λž˜μŠ€κ°€ μ™ΈλΆ€μ—μ„œ 동기화 ν•˜λ„λ‘ λ– λ„˜κΈ°κΈ°
    • java.util (Vector, HashTable μ œμ™Έ)
  2. 동기화λ₯Ό λ‚΄λΆ€μ—μ„œ μˆ˜ν–‰ν•΄ μŠ€λ ˆλ“œ μ•ˆμ „ 클래슀둜 λ§Œλ“€κΈ°
    • μ™ΈλΆ€μ—μ„œ 객체 전체에 락을 κ±°λŠ” 것 보닀 λ™μ‹œμ„±μ„ μ›”λ“±νžˆ κ°œμ„  ν•  수 μžˆμ„λ•Œλ§Œ μ‚¬μš©.
    • java.util.concurrent
    • StringBuffer λŠ” 이 λ°©μ‹μœΌλ‘œ μ„€κ³„λ˜μ—ˆλ‹€. ν•˜μ§€λ§Œ StringBuffer λŠ” 보톡 단일 μŠ€λ ˆλ“œμ—μ„œ μ‚¬μš©ν•˜κΈ°μ—, 이 방법이 μ„±λŠ₯을 λ–¨μ–΄λœ¨λ Έλ‹€.
      • κ·Έ κ²°κ³Ό λ‚΄λΆ€ 동기화λ₯Ό ν•˜μ§€ μ•ŠλŠ” StringBuilder κ°€ λ‚˜μ™”λ‹€.