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 ํ˜ธ์ถœ ์ „ํ›„๋กœ ์กฐ๊ฑด์ด ๋งŒ์กฑํ•˜๋Š”์ง€๋ฅผ ๊ฒ€์‚ฌํ•œ๋‹ค.