item 81 leekyunghee - JAVA-JIKIMI/EFFECTIVE-JAVA3 GitHub Wiki
wait์ notify ๋ณด๋ค๋ ๋์์ฑ ์ ํธ๋ฆฌํฐ๋ฅผ ์ ์ฉํ๋ผ
์ฐ๋ ๋์ ์คํ์์์ ๋๊ธฐํ
์ฐ๋ ๋์ ์คํ์์๋ ์์ค์ฝ๋๊ฐ ๋์ด๋ ์์์ ๋ค๋ฅผ ์ ์๋ค.
- wait() : ์ด๋ค ๊ฐ์ฒด์ ๋ํด ์ฐ๋ ๋๋ฅผ ๋๊ธฐํ๊ฒ ๋ง๋ ๋ค.
- notify() : ๊ฐ์ฒด์ ๋ํด ๋๊ธฐ์ค์ธ ์ฐ๋ ๋๊ฐ ์์ ๊ฒฝ์ฐ ์ฐ์ ์์๊ฐ ๋์ ์ฐ๋ ๋ ํ๋๋ง์ ๊นจ์ด๋ค.
- notifyAll() : ๋๊ธฐ์ค์ธ ์ฐ๋ ๋ ๋ชจ๋ ๊นจ์ด๋ค.
wait์ notifyAll(notify) ๋ฉ์๋๋ ๋๊ธฐํ ์ฒ๋ฆฌ๋ฅผ ํด์, ํ ์๊ฐ์ ํ๋์ ์ฐ๋ ๋๋ง ํธ์ถ์ด ๊ฐ๋ฅํ๋๋ก ํด์ผํ๋ค.
wait๋ฉ์๋๋ ์ฐ์ด์ ํธ์ถ์ด ๊ฐ๋ฅํ๋ค. = ๋ค๋ฅธ ์ฐ๋ ๋์ ์ํด ๋ ๋ค์ ํธ์ถ์ด ๊ฐ๋ฅํ๋ค.
์ง๊ธ์ wait์ notify๋ฅผ ์ฌ์ฉํด์ผ ํ ์ด์ ๊ฐ ๋ง์ด ์ค์๋ค.
- ์๋ฐ 5์์ ๋์ ๋ ๊ณ ์์ค์ ๋์์ฑ ์ ํธ๋ฆฌํฐ๊ฐ ์ด์ ์ด๋ผ๋ฉด wait์ notify๋ก ํ๋์ฝ๋ฉํด์ผ ํ๋ ์ ํ์ ์ธ ์ผ๋ค์ ๋์ ์ฒ๋ฆฌํด์ฃผ๊ธฐ ๋๋ฌธ์ด๋ค.
- wait์ notify๋ ์ฌ๋ฐ๋ฅด๊ฒ ์ฌ์ฉํ๊ธฐ๊ฐ ์์ฃผ ๊น๋ค๋ก์ฐ๋ ๊ณ ์์ค ๋์์ฑ ์ ํธ๋ฆฌํฐ๋ฅผ ์ฌ์ฉํ์.
java.util.concurrent์ ๊ณ ์์ค ์ ํธ๋ฆฌํฐ๋ ์ธ ๋ฒ์ฃผ๋ก ๋๋ ์ ์๋ค.
๋ฐ๋ก Excutor framework, ๋์์ฑ ์ปฌ๋ ์ , ๋๊ธฐํ ์ฅ์น(synchronizer)๋ค.
- ๋์์ฑ ์ปฌ๋ ์ ์ List, Queue, Map ๊ฐ์ ํ์ค ์ปฌ๋ ์ ์ธํฐํ์ด์ค์ ๋์์ฑ์ ๊ฐ๋ฏธํด ๊ตฌํํ ๊ณ ์ฑ๋ฅ ์ปฌ๋ ์ ์ด๋ค. ๋์ ๋์์ฑ์ ๋๋ฌํ๊ธฐ ์ํด ๋๊ธฐํ๋ฅผ ๊ฐ์์ ๋ด๋ถ์์ ์ํํ๋ค. (์์ดํ 79).
- ๋ฐ๋ผ์ ๋์์ฑ ์ปฌ๋ ์ ์์ ๋์์ฑ์ ๋ฌด๋ ฅํํ๋ ๊ฑด ๋ถ๊ฐ๋ฅํ๋ฉฐ ์ธ๋ถ์์ ๋ฝ์ ์ถ๊ฐ๋ก ์ฌ์ฉํ๋ฉด ์คํ๋ ค ์๋๊ฐ ๋๋ ค์ง๋ค.
- ๋์์ฑ ์ปฌ๋ ์ ์์ ๋์์ฑ์ ๋ฌด๋ ฅํํ์ง ๋ชปํ๋ฏ๋ก ์ฌ๋ฌ ๋ฉ์๋๋ฅผ ์์์ ์ผ๋ก ๋ฌถ์ด ํธ์ถํ๋ ์ผ ์ญ์ ๋ถ๊ฐ๋ฅํ๋ค.
๊ทธ๋์ ์ฌ๋ฌ ๊ธฐ๋ณธ ๋์์ ํ๋์ ์์์ ๋์์ผ๋ก ๋ฌถ๋ ์ํ ์์กด์ ์์ ๋ฉ์๋๋ค์ด ์ถ๊ฐ๋์๋ค. ์ด ๋ฉ์๋๋ค์ ์์ฃผ ์ ์ฉํด์ ์๋ฐ 8์์๋ ์ผ๋ฐ ์ปฌ๋ ์ ์ธํฐํ์ด์ค์๋ ๋ํดํธ ๋ฉ์๋(์์ดํ 21) ํํ๋ก ์ถ๊ฐ๋์๋ค.
- ์๋ฅผ ๋ค์ด Map์ putIfAbset(key, value) ๋ฉ์๋๋ ์ฃผ์ด์ง ํค์ ๋งคํ๋ ๊ฐ์ด ์์ง ์์ ๋๋ง ์ ๊ฐ์ ์ง์ด๋ฃ๋๋ค. ๊ทธ๋ฆฌ๊ณ ๊ธฐ์กด ๊ฐ์ด ์์๋ค๋ฉด ๊ทธ ๊ฐ์ ๋ฐํํ๊ณ ์์๋ค๋ฉด null์ ๋ฐํํ๋ค. ์ด ๋ฉ์๋ ๋์ ์ค๋ ๋ ์์ ํ ์ ๊ทํ ๋งต(canonicalizing map)์ ์ฝ๊ฒ ๊ตฌํํ ์ ์๋ค.
// ConcurrentMap์ผ๋ก ๊ตฌํํ ๋์์ฑ ์ ๊ทํ ๋งต
public class Intern {
// ์ฝ๋ 81-1 ConcurrentMap์ผ๋ก ๊ตฌํํ ๋์์ฑ ์ ๊ทํ ๋งต - ์ต์ ์ ์๋๋ค. (432์ชฝ)
private static final ConcurrentMap<String, String> map = new ConcurrentHashMap<>();
public static String intern(String s) {
String previousValue = map.putIfAbsent(s, s);
return previousValue == null ? s : previousValue;
}
}
- CuncurrentHashMap์ get ๊ฐ์ ๊ฒ์ ๊ธฐ๋ฅ์ ์ต์ ํ ๋์๋ค.
- ๋ฐ๋ผ์ get์ ๋จผ์ ํธ์ถํ์ฌ ํ์ํ ๋๋ง putIfAbsent๋ฅผ ํธ์ถํ๋ฉด ๋ ๋น ๋ฅด๋ค.
public class Intern {
private static final ConcurrentMap<String, String> map = new ConcurrentHashMap<>();
// ์ฝ๋ 81-2 ConcurrentMap์ผ๋ก ๊ตฌํํ ๋์์ฑ ์ ๊ทํ ๋งต - ๋ ๋น ๋ฅด๋ค! (432์ชฝ)
public static String intern(String s) {
String result = map.get(s);
if (result == null) {
result = map.putIfAbsent(s, s);
if (result == null)
result = s;
}
return result;
}
}
- CuncurrentHashMap์ ๋์์ฑ์ด ๋ฐ์ด๋๋ฉฐ ์๋๋ ๋ฌด์ฒ ๋น ๋ฅด๋ค. String.intern๋ณด๋ค 6๋ฐฐ๋ ๋น ๋ฅด๋ค.
- ๋์์ฑ ์ปฌ๋ ์ ์ ๋๊ธฐํํ ์ปฌ๋ ์ ์ ๋ก์ ์ ์ฐ์ผ๋ก ๋ง๋ค์ด๋ฒ๋ ธ๋ค. ๋ํ์ ์ธ ์๋ก ์ด์ ๋ Collections.synchronizedMap ๋ณด๋ค๋ ConcurrentHashMap์ ์ฌ์ฉํ๋ ๊ฒ ํจ์ฌ ์ข๋ค.
- ๋๊ธฐํ๋ ๋งต์ ๋์์ฑ ๋งต์ผ๋ก ๊ต์ฒดํ๋ ๊ฒ๋ง์ผ๋ก ๋์์ฑ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ฑ๋ฅ์ ๊ทน์ ์ผ๋ก ๊ฐ์ ๋๋ค.
- ์ปฌ๋ ์ ์ธํฐํ์ด์ค์ค ์ผ๋ถ๋ ์์ ์ด ์ฑ๊ณต์ ์ผ๋ก ์๋ฃ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฌ๋๋ก (์ฆ, ์ฐจ๋จ๋๋๋ก) ํ์ฅ๋์๋ค.
- Queue๋ฅผ ํ์ฅํ BlockingQueue์ ์ถ๊ฐ๋ ๋ฉ์๋ ์ค take๋ ํ์ ์ฒซ ์์๋ฅผ ๊บผ๋ธ๋ค.
- ์ด๋ ๋ง์ฝ ํ๊ฐ ๋น์ด์๋ค๋ฉด ์๋ก์ด ์์๊ฐ ์ถ๊ฐ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฐ๋ค. ์ด๋ฐ ํน์ฑ ๋์ BlockingQueue๋ ์์ ํ(์์ฐ์-์๋น์ ํ)๋ก ์ฐ๊ธฐ์ ์ ํฉํ๋ค.
- ์์ ํ๋ ํ๋ ์ด์์ ์์ฐ์(producer) ์ค๋ ๋๊ฐ ์์ (work)์ ํ์ ์ถ๊ฐํ๊ณ , ํ๋ ์ด์์ ์๋น์(consumer) ์ค๋ ๋๊ฐ ํ์ ์๋ ์์ ์ ๊บผ๋ด ์ฒ๋ฆฌํ๋ ํํ๋ค.
ThreadPoolExecutor๋ฅผ ํฌํจํ ๋๋ถ๋ถ์ Excutor Service ๊ตฌํ์ฒด์์ BlockingQueue๋ฅผ ์ฌ์ฉํ๋ค.
๋๊ธฐํ ์ฅ์น๋ ์ค๋ ๋๊ฐ ๋ค๋ฅธ ์ค๋ ๋๋ฅผ ๊ธฐ๋ค๋ฆด ์ ์๊ฒํ์ฌ, ์๋ก ์์ ์ ์กฐ์จํ ์ ์๊ฒ ํด์ค๋ค.
- ๊ฐ์ฅ ์์ฃผ ์ฐ์ด๋ CountDownLatch์ Semaphore
- CyclicBarrier ์ Exchanger๋ ๊ทธ๋ณด๋ค ๋ ์ฐ์ธ๋ค.
- ๊ฐ์ฅ ๊ฐ๋ ฅํ ๋๊ธฐํ ์ฅ์น๋ Phaser๋ค.
- ์นด์ดํธ๋ค์ด ๋์น๋ ์ผํ์ฑ ์ฅ๋ฒฝ์ผ๋ก ํ๋ ์ด์์ ์ค๋ ๋๊ฐ ๋ ๋ค๋ฅธ ํ๋ ์ด์์ ์ค๋ ๋ ์์ ์ด ๋๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฌ๊ฒ ํ๋ค.
- CountDownLatch์ ์ ์ผํ ์์ฑ์๋ int ๊ฐ์ ๋ฐ์ผ๋ฉฐ, ์ด ๊ฐ์ด ๋์น์ countDown ๋ฉ์๋๋ฅผ ๋ช๋ฒ ํธ์ถํด์ผ ๋๊ธฐ์ค์ธ ์ค๋ ๋๋ค์ ๊นจ์ฐ๋์ง๋ฅผ ๊ฒฐ์ ํ๋ค.
์ด๋ค ๋์๋ค์ ๋์์ ์์ํด ๋ชจ๋ ์๋ฃํ๊ธฐ๊น์ง์ ์๊ฐ์ ์ฌ๋ ๊ฐ๋จํ ํ๋ ์์ํฌ๋ฅผ ๊ตฌ์ถํ๋ค๊ณ ํด๋ณด์.
- ์นด์ดํธ๋ค์ด ๋์น 3๊ฐ ์ฌ์ฉ
- ready Latch : ์์ ์ ์ค๋ ๋๋ค์ด ์ค๋น๊ฐ ์๋ฃ๋์์์ ํ์ด๋จธ ์ค๋ ๋์ ํต์งํ ๋ ์ฌ์ฉํ๋ค.
- ํต์ง๋ฅผ ๋๋ธ ์์ ์ ์ค๋ ๋๋ค์ ๋ ๋ฒ์งธ ๋์น์ธ start๊ฐ ์ด๋ฆฌ๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฐ๋ค.
- ๋ง์ง๋ง ์์ ์ ์ค๋ ๋๊ฐ ready.countDown์ ํธ์ถํ๋ฉด ํ์ด๋จธ ์ค๋ ๋๊ฐ ์์ ์๊ฐ์ ๊ธฐ๋กํ๊ณ start.countDown์ ํธ์ถํ๋ฉด ํ์ด๋จธ ์ค๋ ๋๊ฐ ์์ ์๊ฐ์ ๊ธฐ๋กํ๊ณ start.countDown์ ํธ์ถํ์ฌ ๊ธฐ๋ค๋ฆฌ๋ ์์ ์ ์ค๋ ๋๋ค์ ๊นจ์ด๋ค.
- ๊ทธ ์งํ ํ์ด๋จธ ์ค๋ ๋๋ ์ธ๋ฒ์งธ ๋์น์ธ done์ด ์ด๋ฆฌ๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฐ๋ค.
- done ๋์น๋ ๋ง์ง๋ง ๋จ์ ์์ ์ ์ค๋ ๋๊ฐ ๋์์ ๋ง์น๊ณ done.countDown์ ํธ์ถํ๋ฉด ์ด๋ฆฐ๋ค.
- ํ์ด๋จธ ์ค๋ ๋๋ done ๋์น๊ฐ ์ด๋ฆฌ์๋ง์ ๊นจ์ด๋ ์ข ๋ฃ ์๊ฐ์ ๊ธฐ๋กํ๋ค.
// ์ฝ๋ 81-3 ๋์ ์คํ ์๊ฐ์ ์ฌ๋ ๊ฐ๋จํ ํ๋ ์์ํฌ (433-434์ชฝ)
public class ConcurrentTimer {
//์ด ๋์์ ์คํํ excutor์ ๋ช ๊ฐ๋ ๋์์ ์ํํ ์ ์๋์ง๋ฅผ ๋ปํ๋ ๋์์ฑ ์์ค ๋ฑ)
public static long time(Executor executor, int concurrency, Runnable action) throws InterruptedException {
CountDownLatch ready = new CountDownLatch(concurrency);
CountDownLatch start = new CountDownLatch(1);
CountDownLatch done = new CountDownLatch(concurrency);
for (int i = 0; i < concurrency; i++) {
executor.execute(() -> {
ready.countDown(); // ํ์ด๋จธ์๊ฒ ์ค๋น๋ฅผ ๋ง์ณค์์ ์๋ฆฐ๋ค.
try {
start.await(); // ๋ชจ๋ ์์
์ ์ค๋ ๋๊ฐ ์ค๋น๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฐ๋ค.
action.run();
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
} finally {
done.countDown(); // ํ์ด๋จธ์๊ฒ ์์
์ ๋ง์ณค์์ ์๋ฆฐ๋ค.
}
});
}
ready.await(); // ๋ชจ๋ ์์
์๊ฐ ์ค๋น๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฐ๋ค.
long startNanos = System.nanoTime();
start.countDown(); // ์์
์๋ค์ ๊นจ์ด๋ค.
done.await(); // ๋ชจ๋ ์์
์๊ฐ ์ผ์ ๋๋ง์น๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฐ๋ค.
return System.nanoTime() - startNanos;
}
}
ํต์ฌ ์ ๋ฆฌ
-
์๋ก์ด ์ฝ๋๋ผ๋ฉด ์ธ์ ๋ wait์ notify๊ฐ ์๋ ๋์์ฑ ์ ํธ๋ฆฌํฐ๋ฅผ ์จ์ผํ๋ค.
-
wait ๋ฉ์๋๋ ์ค๋ ๋๊ฐ ์ด๋ค ์กฐ๊ฑด์ด ์ถฉ์กฑ๋๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฌ๊ฒ ํ ๋ ์ฌ์ฉํ๋ค.
-
๋ฝ ๊ฐ์ฒด์ธ wait ๋ฉ์๋๋ ๋ฐ๋์ ๊ทธ ๊ฐ์ฒด๋ฅผ ์ ๋ ๋๊ธฐํ ์์ญ ์์์ ํธ์ถํด์ผ ํ๋ค.
-
wait์ notify๋ฅผ ์ง์ ์ฌ์ฉํ๋ ๊ฒ์ ๋์์ฑ '์ด์ ๋ธ๋ฆฌ ์ธ์ด'๋ก ํ๋ก๊ทธ๋๋ฐํ๋ ๊ฒ์ ๋น์ ํ ์ ์๋ค.
-
๋ฐ๋ฉด java.util.concurrent๋ ๊ณ ์์ค ์ธ์ด์ ๋น์ ํ ์ ์๋ค.
-
์ฝ๋๋ฅผ ์๋ก ์์ฑํ๋ค๋ฉด wait์ notify๋ฅผ ์ธ ์ด์ ๊ฐ ๊ฑฐ์(์ด์ฉ๋ฉด ์ ํ) ์๋ค.
-
wait๋ฅผ ์ฌ์ฉํ๋ ๋ ๊ฑฐ์ ์ฝ๋๋ฅผ ์ ์ง๋ณด์ํด์ผ ํ๋ค๋ฉด wait๋ ํญ์ ํ์ค ๊ด์ฉ๊ตฌ์ ๋ฐ๋ผ while๋ฌธ ์์์ ํธ์ถํ๋๋ก ํ์.