Skip to content

Commit

Permalink
Merge pull request #348 from SujinEmilyCho/week12_sujin
Browse files Browse the repository at this point in the history
[#82][2κΈ°] μŠ€λ ˆλ“œ μ•ˆμ „μ„± μˆ˜μ€€μ„ λ¬Έμ„œν™”ν•˜λΌ
  • Loading branch information
ksy90101 authored Oct 25, 2021
2 parents 0e632d0 + d4d60bb commit f97227d
Showing 1 changed file with 101 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
# μ•„μ΄ν…œ 82. μŠ€λ ˆλ“œ μ•ˆμ •μ„± μˆ˜μ€€μ„ λ¬Έμ„œν™”ν•˜λΌ
μžλ°”λ… κΈ°λ³Έ μ˜΅μ…˜μ—μ„œ μƒμ„±ν•œ API λ¬Έμ„œμ—λŠ” synchronized ν•œμ •μžκ°€ ν¬ν•¨λ˜μ§€ μ•ŠλŠ”λ‹€. λ©”μ„œλ“œ 선언에 synchronized ν•œμ •μžλ₯Ό μ„ μ–Έν• μ§€λŠ” κ΅¬ν˜„ 이슈일 뿐 API에 μ†ν•˜μ§€ μ•ŠλŠ”λ‹€.

### ν΄λž˜μŠ€κ°€ μ§€μ›ν•˜λŠ” μŠ€λ ˆλ“œ μ•ˆμ „μ„± μˆ˜μ€€
1. λΆˆλ³€(immutabile)
- 이 클래슀의 μΈμŠ€ν„΄μŠ€λŠ” 마치 μƒμˆ˜μ™€ κ°™μ•„μ„œ μ™ΈλΆ€ 동기화도 ν•„μš” μ—†λ‹€.
- ex. String, Long, BigInteger λ“±
2. 무쑰건적 μŠ€λ ˆλ“œ μ•ˆμ „(unconditionally thread-safe)
- 이 클래슀의 μΈμŠ€ν„΄μŠ€λŠ” μˆ˜μ •λ  수 μžˆμœΌλ‚˜, λ‚΄λΆ€μ—μ„œ μΆ©μ‹€νžˆ λ™κΈ°ν™”ν•˜μ—¬ λ³„λ„μ˜ μ™ΈλΆ€ 동기화 없이 λ™μ‹œμ— μ‚¬μš©ν•΄λ„ μ•ˆμ „ν•˜λ‹€.
- ex. AtomicLong, ConcurrentHashMap λ“±
3. 쑰건뢀 μŠ€λ ˆλ“œ μ•ˆμ „(contiditionally thread-safe)
- 무쑰건적 μŠ€λ ˆλ“œ μ•ˆμ „κ³Ό κ°™μœΌλ‚˜, 일뢀 λ©”μ„œλ“œλŠ” λ™μ‹œμ— μ‚¬μš©ν•˜λ €λ©΄ μ™ΈλΆ€ 동기화가 ν•„μš”ν•˜λ‹€
- ex. Collections.synchronized 래퍼 λ©”μ„œλ“œκ°€ λ°˜ν™˜ν•œ μ»¬λ ‰μ…˜λ“€μ΄ 여기에 μ†ν•œλ‹€(이 μ»¬λ ‰μ…˜λ“€μ΄ λ°˜ν™˜ν•œ λ°˜λ³΅μžλŠ” μ™ΈλΆ€μ—μ„œ 동기화해야 ν•œλ‹€)
4. μŠ€λ ˆλ“œ μ•ˆμ „ν•˜μ§€ μ•ŠμŒ(not thread-safe)
- 이 ν΄λž˜μŠ€λ“€μ˜ μΈμŠ€ν„΄μŠ€λŠ” μˆ˜μ •λ  수 μžˆλ‹€. λ™μ‹œμ— μ‚¬μš©ν•˜λ €λ©΄ 각각의(ν˜Ήμ€ 일련의) λ©”μ„œλ“œ ν˜ΈμΆœμ„ ν΄λΌμ΄μ–ΈνŠΈκ°€ μ„ νƒν•œ μ™ΈλΆ€ 동기화 λ©”μ»€λ‹ˆμ¦˜μœΌλ‘œ 감싸야 ν•œλ‹€.
- ex. ArrayList, HashMap 같은 κΈ°λ³Έ μ»¬λ ‰μ…˜μ΄ μ—¬κΈ° μ†ν•œλ‹€.
5. μŠ€λ ˆλ“œ μ λŒ€μ (thread-hostile)
- 이 ν΄λž˜μŠ€λŠ” λͺ¨λ“  λ©”μ„œλ“œ ν˜ΈμΆœμ„ μ™ΈλΆ€ λ™κΈ°ν™”λ‘œ 감싸더라도 λ©€ν‹°μŠ€λ ˆλ“œ ν™˜κ²½μ—μ„œ μ•ˆμ „ν•˜μ§€ μ•Šλ‹€. 이 μˆ˜μ€€μ˜ ν΄λž˜μŠ€λŠ” 일반적으둜 정적 데이터λ₯Ό 아무 동기화 없이 μˆ˜μ •ν•œλ‹€. 이런 클래슀λ₯Ό 고의적으둜 λ§Œλ“œλŠ” μ‚¬λžŒμ€ μ—†κ² μ§€λ§Œ, λ™μ‹œμ„±μ„ κ³ λ €ν•˜μ§€ μ•Šκ³  μž‘μ„±ν•˜λ‹€ 보면 μš°μ—°νžˆ λ§Œλ“€μ–΄μ§ˆ 수 μžˆλ‹€. μŠ€λ ˆλ“œ μ λŒ€μ μœΌλ‘œ λ°ν˜€μ§„ ν΄λž˜μŠ€λ‚˜ λ©”μ„œλ“œλŠ” 일반적으둜 문제λ₯Ό 고쳐 μž¬λ°°ν¬ν•˜κ±°λ‚˜ μ‚¬μš© 자제(deprecated) API둜 μ§€μ •ν•œλ‹€.
- ex. μ•„μ΄ν…œ 78의 generateSerialNumber λ©”μ„œλ“œμ— λ‚΄λΆ€ 동기화λ₯Ό μƒλž΅ν•œ 경우

### μŠ€λž˜λ“œ μ•ˆμ „μ„± μ• λ„ˆν…Œμ΄μ…˜
- `@Immutable`
- `@ThreadSafe`: unconditionally thread-safe, conditionalluy thread-safe
- `@NotThreadSafe`

### μ™ΈλΆ€ 동기화 vs λ‚΄λΆ€ 동기화
```java
public class Foo {
private int count;
public void addToCount() {
count++;
log.info("count increased to " + count);
}
}

// μ™ΈλΆ€ 동기화
synchronized (foo) {
foo.addToCount();
}
```

```java
// λ‚΄λΆ€ 동기화
public class Foo {
private int count;

public void addToCount() {
int val;
synchronized (this) {
val = ++count;
}
// this log call should not be synchronized since it does IO
log.info("count increased to " + val);
}
}
```
β†’ μ™ΈλΆ€ 동기화, λ‚΄λΆ€ 동기화λ₯Ό μ•Œμ•„λ³΄κΈ° μœ„ν•œ μ˜ˆμ‹œμΌ 뿐 μ‹€μ œλ‘œλŠ” AtomicInteger을 μ‚¬μš©ν•˜λŠ” 것이 κ°€μž₯ μ’‹λ‹€.

### μŠ€λ ˆλ“œ μ•ˆμ „μ„± μˆ˜μ€€ λ¬Έμ„œν™”
- 클래슀의 μŠ€λ ˆλ“œ μ•ˆμ „μ„±μ€ 보톡 클래슀의 λ¬Έμ„œν™” 주석에 κΈ°μž¬ν•˜μ§€λ§Œ, λ…νŠΉν•œ νŠΉμ„±μ˜ λ©”μ„œλ“œλΌλ©΄ ν•΄λ‹Ή λ©”μ„œλ“œμ˜ 주석에 κΈ°μž¬ν•œλ‹€
- μ—΄κ±° νƒ€μž…μ€ ꡳ지 λΆˆλ³€μ΄λΌκ³  쓰지 μ•Šμ•„λ„ λœλ‹€
- λ°˜ν™˜ νƒ€μž…λ§ŒμœΌλ‘œ λͺ…ν™•νžˆ μ•Œ 수 μ—†λŠ” 정적 νŒ©ν„°λ¦¬λΌλ©΄ μžμ‹ μ΄ λ°˜ν™˜ν•˜λŠ” 객체의 μŠ€λ ˆλ“œ μ•ˆμ „μ„±μ„ λ°˜λ“œμ‹œ λ¬Έμ„œν™” ν•΄μ•Όν•œλ‹€
- 쑰건뢀 μŠ€λ ˆλ“œ μ•ˆμ „ν•œ ν΄λž˜μŠ€λŠ” μ£Όμ˜ν•΄μ„œ λ¬Έμ„œν™”ν•΄μ•Ό ν•œλ‹€. μ–΄λ–€ μˆœμ„œλ‘œ ν˜ΈμΆœν•  λ•Œ μšλΆ€ 동기화가 ν•„μš”ν•œμ§€, 그리고 κ·Έ μˆœμ„œλ‘œ ν˜ΈμΆœν•˜λ €λ©΄ μ–΄λ–€ 락 ν˜Ήμ€ (λ“œλ¬Όκ²Œ) 락듀을 μ–»μ–΄μ•Ό ν•˜λŠ”μ§€ μ•Œλ €μ€˜μ•Ό ν•œλ‹€. 일반적으둜 μΈμŠ€ν„΄μŠ€ 자체λ₯Ό 락으둜 μ–»μ§€λ§Œ μ˜ˆμ™Έλ„ μžˆλ‹€.

```java
// Collections.synchronizedMap API μ˜ˆμ‹œ
synchornizedMap이 λ°˜ν™˜ν•œ 맡의 μ»¬λ ‰μ…˜ λ·°λ₯Ό μˆœνšŒν•˜λ €λ©΄ λ°˜λ“œμ‹œ κ·Έ 맡을 락으둜 μ‚¬μš©ν•΄ μˆ˜λ™μœΌλ‘œ λ™κΈ°ν™”ν•˜λΌ.

Map<K, V> m = Collections.synchronizedMap(new HashMap<>());
Set<K> s = m.keySet(); // 동기화 뢈둝 밖에 μžˆμ–΄λ„ λœλ‹€.

synchronized(m) { // sκ°€ μ•„λ‹Œ m을 μ‚¬μš©ν•΄ 동기화 ν•΄μ•Όν•œλ‹€!
for (K key : s)
key.f();
}
```

### 곡개 락

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

```java
private final Object lock = new Object();

public void foo() {
synchronized(lock) {
...
}
}
```
β†’ λΉ„κ³΅κ°œ 락 κ°μ²΄λŠ” 클래슀 λ°”κΉ₯μ—μ„œ λ³Ό 수 μ—†μœΌλ‹ˆ ν΄λΌμ΄μ–ΈνŠΈκ°€ κ·Έ 객체의 동기화에 κ΄€μ—¬ν•  수 μ—†λ‹€
(락 객체λ₯Ό 동기화 λŒ€μƒ 객체 μ•ˆμœΌλ‘œ μΊ‘μŠν™”)
β‡’ λΉ„κ³΅κ°œ 락 객체 κ΄€μš©κ΅¬λŠ” 무쑰건 μŠ€λ ˆλ“œ μ•ˆμ „ ν΄λž˜μŠ€μ—μ„œλ§Œ μ‚¬μš©ν•  수 μžˆλ‹€
β†’ μƒμ†μš©μœΌλ‘œ μ„€κ³„ν•œ ν΄λž˜μŠ€μ— 특히 잘 λ§žλŠ”λ‹€
(μƒμ†μš© ν΄λž˜μŠ€μ—μ„œ μžμ‹ μ˜ μΈμŠ€ν„΄μŠ€λ₯Ό 락으둜 μ‚¬μš©ν•œλ‹€λ©΄, ν•˜μœ„ ν΄λž˜μŠ€λŠ” μ•„μ£Ό μ‰½κ²Œ μ˜λ„μΉ˜μ•Šκ²Œ 기반 클래슀의 λ™μž‘μ„ λ°©ν•΄ν•  수 μžˆλ‹€)

### 정리
λͺ¨λ“  ν΄λž˜μŠ€κ°€ μžμ‹ μ˜ μŠ€λ ˆλ“œ μ•ˆμ „μ„± 정보λ₯Ό λͺ…ν™•νžˆ λ¬Έμ„œν™” ν•΄μ•Ό ν•œλ‹€. μ •ν™•ν•œ μ–Έμ–΄λ‘œ μ •ν™•νžˆ μ„€λͺ…ν•˜κ±°λ‚˜ μŠ€λ ˆλ“œ μ•ˆμ „μ„± μ• λ„ˆν…Œμ΄μ…˜μ„ μ‚¬μš©ν•  수 μžˆλ‹€. synchronized ν•œμ •μžλŠ” λ¬Έμ„œν™”μ™€ 관련이 μ—†λ‹€. 쑰건뢀 μŠ€λ ˆλ“œ μ•ˆμ „ ν΄λž˜μŠ€λŠ” λ©”μ„œλ“œλ₯Ό μ–΄λ–€ μˆœμ„œλ‘œ ν˜ΈμΆœν•  λ•Œ μ™ΈλΆ€ 동기화가 μš”κ΅¬λ˜κ³ , κ·Έλ•Œ μ–΄λ–€ 락을 μ–»μ–΄μ•Ό ν•˜λŠ”μ§€λ„ μ•Œλ €μ€˜μ•Ό ν•œλ‹€. 무쑰건적 μŠ€λ ˆλ“œ μ•ˆμ „ 클래슀λ₯Ό μž‘μ„±ν•  λ•ŒλŠ” synchronized λ©”μ„œλ“œκ°€ μ•„λ‹Œ λΉ„κ³΅κ°œ 락 객체λ₯Ό μ‚¬μš©ν•˜μž. μ΄λ ‡κ²Œ ν•΄μ•Ό ν΄λΌμ΄μ–ΈνŠΈλ‚˜ ν•˜μœ„ ν΄λž˜μŠ€μ—μ„œ 동기화 λ©”μ»€λ‹ˆμ¦˜μ„ κΉ¨λœ¨λ¦¬λŠ” κ±Έ μ˜ˆλ°©ν•  수 있고, ν•„μš”ν•˜λ‹€λ… λ‚ŸμŒμ— 더 μ •κ΅ν•œ λ™μ‹œμ„± μ œμ–΄ λ©”μ»€λ‹ˆμ¦˜μœΌλ‘œ μž¬κ΅¬ν˜„ν•  여지가 생긴닀.

0 comments on commit f97227d

Please sign in to comment.