item 81 junghyunlyoo - JAVA-JIKIMI/EFFECTIVE-JAVA3 GitHub Wiki
๋์์ฑ ์ ํธ๋ฆฌํฐ
์์ฆ์ wait์ notify๋ฅผ ์ฌ์ฉํด์ผ ํ ์ด์ ๊ฐ ๋ง์ด ์ค์๋ค.
์๋ํ๋ฉด ์๋ฐ 5์์ ๋์ ๋ ๊ณ ์์ค์ ๋์์ฑ ์ ํธ๋ฆฌํฐ๊ฐ wait์ notify๋ก ํ๋์ฝ๋ฉํด์ผ ํ๋ ์ ํ์ ์ธ ์ผ๋ค์ ๋์ ์ฒ๋ฆฌํด์ฃผ๊ธฐ ๋๋ฌธ์ด๋ค.
wait์ notify๋ ์ฌ๋ฐ๋ฅด๊ฒ ์ฌ์ฉํ๊ธฐ๊ฐ ์์ฃผ ๊น๋ค๋ก์ฐ๋ ๊ณ ์์ค ๋์์ฑ ์ ํธ๋ฆฌํฐ๋ฅผ ์ฌ์ฉํ์.
java.util.concurrent์ ๊ณ ์์ค ์ ํธ๋ฆฌํฐ๋ ์๋์ ๊ฐ์ด ์ธ ๋ฒ์ฃผ๋ก ๋๋ ์ ์๋ค.
-
์คํ์ ํ๋ ์์ํฌ
-
๋์์ฑ ์ปฌ๋ ์ (concurrent collection)
-
๋๊ธฐํ ์ฅ์น(synchronizer)
์คํ์ ํ๋ ์์ํฌ๋ ์ด์ ์ ์ดํด๋ณด์๊ณ (item 80) ์ด๋ฒ ์ฅ์์ ๋์์ฑ ์ปฌ๋ ์ ๊ณผ ๋๊ธฐํ ์ฅ์น๋ฅผ ๋ค๋ฃฐ ๊ฒ์ด๋ค.
๋์์ฑ ์ปฌ๋ ์
๋์์ฑ ์ปฌ๋ ์ ์ List, Queue, Map ๊ฐ์ ํ์ค ์ปฌ๋ ์ ์ธํฐํ์ด์ค์ ๋์์ฑ์ ๊ฐ๋ฏธํด ๊ตฌํํ ๊ณ ์ฑ๋ฅ ์ปฌ๋ ์ ์ด๋ค.
๋์ ๋์์ฑ์ ๋๋ฌํ๊ธฐ ์ํด ๋๊ธฐํ๋ฅผ ๊ฐ์์ ๋ด๋ถ์์ ์ํํ๋ค. (item 79)
๋ฐ๋ผ์ ๋์์ฑ ์ปฌ๋ ์ ์์ ๋์์ฑ์ ๋ฌด๋ ฅํํ๋ ๊ฑด ๋ถ๊ฐ๋ฅํ๋ฉฐ e์ธ๋ถ์์ ๋ฝ์ ์ถ๊ฐ๋ก ์ฌ์ฉํ๋ฉด ์คํ๋ ค ์๋๊ฐ ๋๋ ค์ง๋ค.
๋์์ฑ ์ปฌ๋ ์ ์์ ๋์์ฑ์ ๋ฌด๋ ฅํํ์ง ๋ชปํ๋ฏ๋ก ์ฌ๋ฌ ๋ฉ์๋๋ฅผ ์์์ ์ผ๋ก ๋ฌถ์ด ํธ์ถํ๋ ์ผ ์ญ์ ๋ถ๊ฐ๋ฅํ๋ค.
๊ทธ๋์ ์ฌ๋ฌ ๊ธฐ๋ณธ ๋์์ ํ๋์ ์์์ ๋์์ผ๋ก ๋ฌถ๋ '์ํ ์์กด์ ์์ ' ๋ฉ์๋๋ค์ด ์ถ๊ฐ๋์๋ค.
์ด ๋ฉ์๋๋ค์ ์์ฃผ ์ ์ฉํด์ ์๋ฐ 8์์๋ ์ผ๋ฐ ์ปฌ๋ ์ ์ธํฐํ์ด์ค์๋ default method(item 21) ํํ๋ก ์ถ๊ฐ๋์๋ค.
์๋ฅผ ๋ค์ด Map์ putIfAbsent(key, value) ๋ฉ์๋๋ ์ฃผ์ด์ง ํค์ ๋งคํ๋ ๊ฐ์ด ์์ง ์์ ๋๋ง ์ ๊ฐ์ ์ง์ด๋ฃ๋๋ค.
๊ทธ๋ฆฌ๊ณ ๊ธฐ์กด ๊ฐ์ด ์์๋ค๋ฉด ๊ทธ ๊ฐ์ ๋ฐํํ๊ณ ์์๋ค๋ฉด null์ ๋ฐํํ๋ค.
์ด ๋ฉ์๋ ๋์ ์ค๋ ๋ ์์ ํ ์ ๊ทํ ๋งต(canonicalizing map)์ ์ฝ๊ฒ ๊ตฌํํ ์ ์๋ค.
๋ค์์ String.intern์ ๋์์ ํ๋ด ๋ด์ด ๊ตฌํํ ๋ฉ์๋๋ค.
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;
}
์์ง ๊ฐ์ ํ ์ ์ด ์๋ค. ConcurrentHashMap์ get๊ณผ ๊ฐ์ ๊ฒ์ ๊ธฐ๋ฅ์ ์ต์ ํ ๋์ด ์๊ธฐ ๋๋ฌธ์ get์ ์ด์ฉํ์ฌ ํ์ํ ๋๋ง putIfAbsent๋ฅผ ํธ์ถํ๋๋ก ์์ ํ๋ฉด ๋ ํจ์จ์ ์ด๋ค.
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;
}
ConcurrentHashMap์ ๋์์ฑ์ด ๋ฐ์ด๋๋ฉฐ ์๋๋ ๋ฌด์ฒ ๋น ๋ฅด๋ค. ์ด๋ฌํ ๋์์ฑ ์ปฌ๋ ์ ์ ๋๊ธฐํํ ์ปฌ๋ ์ ์ ๋ก์ ์ ์ฐ์ผ๋ก ๋ง๋ค์ด ๋ฒ๋ ธ๋ค.
Collections.synchronizedMap ๋ณด๋ค๋ ConcurrentHashMap์ ์ฌ์ฉํ๋ ๊ฒ ํจ์ฌ ํจ์จ์ ์ด๋ค.
์ปฌ๋ ์ ์ธํฐํ์ด์ค ์ค ์ผ๋ถ๋ ์์ ์ด ์ฑ๊ณต์ ์ผ๋ก ์๋ฃ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฌ๋๋ก(์ฆ ์ฐจ๋จ๋๋๋ก) ํ์ฅ๋์๋ค.
Queue๋ฅผ ํ์ฅํ BlockingQueue๋ฅผ ์ดํด๋ณด์. BlockingQueue์ ์ถ๊ฐ๋ ๋ฉ์๋ ์ค take๋ ํ์ ์ฒซ ์์๋ฅผ ๊บผ๋ธ๋ค.
์ด๋ ๋ง์ฝ ํ๊ฐ ๋น์๋ค๋ฉด ์๋ก์ด ์์๊ฐ ์ถ๊ฐ๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฐ๋ค. ์ด๋ฐ ํน์ฑ ๋์ BlockingQueue๋ ์์ ํ(์์์-์๋น์ ํ)๋ก ์ฐ๊ธฐ์ ์ ํฉํ๋ค.
์์ ํ๋ ํ๋ ์ด์์ ์์์(producer) ์ค๋ ๋๊ฐ ์์ (work) ์ ํ์ ์ถ๊ฐํ๊ณ ํ๋ ์ด์์ ์๋น์(consumer) ์ค๋ ๋๊ฐ ํ์ ์๋ ์์ ์ ๊บผ๋ด ์ฒ๋ฆฌํ๋ ํํ๋ค.
ThreadPoolExecutor๋ฅผ ํฌํจํ ๋๋ถ๋ถ์ ์คํ์ ์๋น์ค(item 80) ๊ตฌํ์ฒด์์ BlockingQueue๋ฅผ ์ฌ์ฉํ๋ค.
๋๊ธฐํ ์ฅ์น
๋๊ธฐํ ์ฅ์น๋ ์ค๋ ๋๊ฐ ๋ค๋ฅธ ์ค๋ ๋๋ฅผ ๊ธฐ๋ค๋ฆด ์ ์๊ฒ ํ์ฌ ์๋ก ์์ ์ ์กฐ์จํ ์ ์๊ฒ ํด์ค๋ค.
๋๊ธฐํ ์ฅ์น์ ๋ํ์ ์ธ ์๋ก๋ CountDownLatch๊ฐ ์๋ค.
CountDownLatch๋ ์ผํ์ฑ ์ฅ๋ฒฝ์ผ๋ก, ํ๋ ์ด์์ ์ค๋ ๋๊ฐ ๋ ๋ค๋ฅธ ํ๋ ์ด์์ ์ค๋ ๋ ์์ ์ด ๋๋ ๋๊น์ง ๊ธฐ๋ค๋ฆฌ๊ฒ ํ๋ค.
CountDownLatch๋ ์์ฑ์๋ฅผ 1๊ฐ๋ง ๊ฐ์ง๊ณ ์๋ค. ์ด ์์ฑ์์ ๋งค๊ฐ๋ณ์์ธ int๋ CountDownLatch์ countdown ๋ฉ์๋๋ฅผ ๋ช ๋ฒ ํธ์ถํด์ผ ๋๊ธฐ ์ค์ธ ์ค๋ ๋๋ค์ ๊นจ์ฐ๋์ง ๊ฒฐ์ ํ๋ค.
์ด ์ฅ์น๋ฅผ ํ์ฉํ๋ฉด ์ ์ฉํ ๊ธฐ๋ฅ๋ค์ ์ฝ๊ฒ ๊ตฌํํ ์ ์๋ค.
์๋ฅผ ๋ค์ด ์ด๋ค ๋์๋ค์ ๋์์ ์์ํด ๋ชจ๋ ์๋ฃํ๊ธฐ๊น์ง์ ์๊ฐ์ ์ฌ๋ ๊ฐ๋จํ ํ๋ ์์ํฌ๋ฅผ ๊ตฌ์ถํ๋ค๊ณ ํด๋ณด์.
์ด ํ๋ ์์ํฌ๋ ๋ฉ์๋ ํ๋๋ก ๊ตฌ์ฑ๋๋ฉฐ, ์ด ๋ฉ์๋๋ ๋์๋ค์ ์คํํ ์คํ์์ ๋์์ ๋ช ๊ฐ๋ ๋์์ ์ํํ ์ ์๋์ง๋ฅผ ๋ปํ๋ ๋์์ฑ ์์ค์ ๋งค๊ฐ๋ณ์๋ก ๋ฐ๋๋ค.
ํ์ด๋จธ ์ค๋ ๋๊ฐ ์๊ณ๋ฅผ ์์ํ๊ธฐ ์ ์ ๋ชจ๋ ์์ ์ ์ค๋ ๋๋ ๋์์ ์ํํ ์ค๋น๋ฅผ ๋ง์น๋ค.
๋ง์ง๋ง ์์ ์ ์ค๋ ๋๊ฐ ์ค๋น๋ฅผ ๋ง์น๋ฉด ํ์ด๋จธ ์ค๋ ๋๊ฐ '์์ ๋ฐฉ์์ '๋ฅผ ๋น๊ฒจ ์์ ์ ์ค๋ ๋๋ค์ด ์ผ์ ์์ํ๊ฒ ํ๋ค.
๋ง์ง๋ง ์์ ์ ์ค๋ ๋๊ฐ ๋์์ ๋ง์น์๋ง์ ํ์ด๋จธ ์ค๋ ๋๋ ์๊ณ๋ฅผ ๋ฉ์ถ๋ค.
์ด์์ ๊ธฐ๋ฅ์ wait์ notify๋ง์ผ๋ก ๊ตฌํํ๋ ค๋ฉด ์์ฃผ ๋ํดํ๊ณ ์ง์ ๋ถํ ์ฝ๋๊ฐ ๋ง๋ค์ด์ง์ง๋ง CountDownLatch๋ฅผ ์ฐ๋ฉด ์ง๊ด์ ์ผ๋ก ๊ตฌํํ ์ ์๋ค.
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;
}
์ด ์ฝ๋๋ ์นด์ดํธ ๋ค์ด ๋์น๋ฅผ 3๊ฐ ์ฌ์ฉํ๋ค. ready ๋์น๋ ์์ ์ ์ค๋ ๋๋ค์ด ์ค๋น๊ฐ ์๋ฃ๋์์ ํ์ด๋จธ ์ค๋ ๋์ ํต์งํ ๋ ์ฌ์ฉํ๋ค.
ํต์ง๋ฅผ ๋๋ธ ์์ ์ ์ค๋ ๋๋ค์ ๋ ๋ฒ์งธ ๋์น์ธ start๊ฐ ์ด๋ฆฌ๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฐ๋ค.
๋ง์ง๋ง ์์ ์ ์ค๋ ๋๊ฐ ready.countDown์ ํธ์ถํ๋ฉด ํ์ด๋จธ ์ค๋ ๋๊ฐ ์์ ์๊ฐ์ ๊ธฐ๋กํ๊ณ start.countDown์ ํธ์ถํ์ฌ ๊ธฐ๋ค๋ฆฌ๋ ์์ ์ ์ค๋ ๋๋ค์ ๊นจ์ด๋ค.
๊ทธ ์งํ ํ์ด๋จธ ์ค๋ ๋๋ ์ธ ๋ฒ์งธ ๋์น์ธ done์ด ์ด๋ฆฌ๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฐ๋ค. done ๋์น๋ ๋ง์ง๋ง ๋จ์ ์์ ์ ์ค๋ ๋๊ฐ ๋์์ ๋ง์น๊ณ done.countDown์ ํธ์ถํ๋ฉด ์ด๋ฆฐ๋ค.
ํ์ด๋จธ ์ค๋ ๋๋ done ๋์น๊ฐ ์ด๋ฆฌ์๋ง์ ๊นจ์ด๋ ์ข ๋ฃ ์๊ฐ์ ๊ธฐ๋กํ๋ค.
time ๋ฉ์๋์ ๋๊ฒจ์ง ์คํ์(executor)๋ concurrency ๋งค๊ฐ๋ณ์๋ก ์ง์ ํ ๋์์ฑ ์์ค๋งํผ์ ์ค๋ ๋๋ฅผ ์์ฑํ ์ ์์ด์ผ ํ๋ค.
๊ทธ๋ ์ง ๋ชปํ๋ฉด ์ด ๋ฉ์๋๋ ๊ฒฐ์ฝ ๋๋์ง ์์ ๊ฒ์ด๋ค. ์ด๋ฐ ์ํ๋ฅผ ์ค๋ ๋ ๊ธฐ์ ๊ต์ฐฉ์ํ๋ผ ํ๋ค.
InterruptedException์ ์บ์นํ ์์ ์ ์ค๋ ๋๋ Thread.currentThread().interrupt() ๊ด์ฉ๊ตฌ๋ฅผ ์ฌ์ฉํด ์ธํฐ๋ฝํธ๋ฅผ ๋์ด๋ฆฌ๊ณ ์์ ์ run ๋ฉ์๋์์ ๋น ์ ธ๋์จ๋ค.
์ด๋ ๊ฒ ํด์ผ ์คํ์๊ฐ ์ธํฐ๋ฝํธ๋ฅผ ์ ์ ํ๊ฒ ์ฒ๋ฆฌํ ์ ์๋ค.
์ ์ฝ๋์์ System.nanoTime ๋ฉ์๋๋ฅผ ์ฌ์ฉํด ์๊ฐ์ ์ฐ ๊ฒ์ ์ฃผ๋ชฉํ์.
์๊ฐ ๊ฐ๊ฒฉ์ ์ด ๋๋ ํญ์ System.currentTimeMillis๊ฐ ์๋ System.nanoTime์ ์ฌ์ฉํ์.
System.nanoTime์ ๋ ์ ํํ๊ณ ์ ๋ฐํ๋ฉฐ ์์คํ
์ ์ค์๊ฐ ์๊ณ์ ์๊ฐ ๋ณด์ ์ ์ํฅ๋ฐ์ง ์๋๋ค.
ํํธ, ์ด ์์ ์ ์ฝ๋๋ ์์
์ ์ถฉ๋ถํ ์๊ฐ(ex 1์ด ์ด์)์ด ๊ฑธ๋ฆฌ์ง ์๋๋ค๋ฉด ์ ํํ ์๊ฐ์ ์ธก์ ํ ์ ์์ ๊ฒ์ด๋ค.
์ ๋ฐํ ์๊ฐ ์ธก์ ์ ๋งค์ฐ ์ด๋ ค์ด ์์
์ด๋ผ, ๊ผญ ํด์ผ ํ๋ค๋ฉด jmh๊ฐ์ ํน์ ํ๋ ์์ํฌ๋ฅผ ์ฌ์ฉํด์ผ ํ๋ค.
๋์์ฑ ์ ํธ๋ฆฌํฐ๋ฅผ ์ฌ์ฉํ์ง ๋ชป ํ๋ ๊ฒฝ์ฐ
์๋ก์ด ์ฝ๋๋ฅผ ์ง๋ ๊ฒฝ์ฐ๋ผ๋ฉด ํญ์ wait์ notify๊ฐ ์๋ ๋์์ฑ ์ ํธ๋ฆฌํฐ๋ฅผ ์จ์ผ ํ๋ค.
ํ์ง๋ง wait๊ณผ notify๋ฅผ ์ฌ์ฉํ๋ ๋ ๊ฑฐ์ ์ฝ๋๋ฅผ ๋ค๋ค์ผ ํ๋ ๊ฒฝ์ฐ๋ ์์ ๊ฒ์ด๋ค.
wait ๋ฉ์๋๋ ์ค๋ ๋๊ฐ ์ด๋ค ์กฐ๊ฑด์ด ์ถฉ์กฑ๋๊ธฐ๋ฅผ ๊ธฐ๋ค๋ฆฌ๊ฒ ํ ๋ ์ฌ์ฉํ๋ค.
๋ฝ ๊ฐ์ฒด์ wait ๋ฉ์๋๋ ๋ฐ๋์ ๊ทธ ๊ฐ์ฒด๋ฅผ ์ ๊ทผ ๋๊ธฐํ ์์ญ ์์์ ํธ์ถํด์ผ ํ๋ค.
wait์ ์ฌ์ฉํ๋ ํ์ค ๋ฐฉ์์ ์๋์ ๊ฐ๋ค.
synchronized (obj) {
while (<์กฐ๊ฑด์ด ์ถฉ์กฑ๋์ง ์์>){
obj.wait();
}
// ์กฐ๊ฑด์ด ์ถฉ์กฑ๋์ ๋์ ๋์์ ์ํ
}
wait ๋ฉ์๋๋ฅผ ์ฌ์ฉํ ๋๋ ๋ฐ๋์ ๋๊ธฐ ๋ฐ๋ณต๋ฌธ(wait loop) ๊ด์ฉ๊ตฌ๋ฅผ ์ฌ์ฉํ์.
๊ทธ๋ฆฌ๊ณ ๋ฐ๋ณต๋ฌธ ๋ฐ์์๋ ์ ๋๋ก ํธ์ถํ๋ฉด ์๋๋ค. ์ด ๋ฐ๋ณต๋ฌธ์ wait ํธ์ถ ์ ํ๋ก ์กฐ๊ฑด์ด ๋ง์กฑํ๋์ง๋ฅผ ๊ฒ์ฌํ๋ค.