item 48 Jung inchul - JAVA-JIKIMI/EFFECTIVE-JAVA3 GitHub Wiki

Effective Java 3e ์•„์ดํ…œ 48๋ฅผ ์š”์•ฝํ•œ ๋‚ด์šฉ ์ž…๋‹ˆ๋‹ค.

์ฃผ๋ฅ˜ ์–ธ์–ด ์ค‘, ๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ ์ธก๋ฉด์—์„œ ์ž๋ฐ”๋Š” ํ•ญ์ƒ ์•ž์„œ๊ฐ”๋‹ค.

  • 1996๋…„ โ†’ ์Šค๋ ˆ๋“œ, ๋™๊ธฐํ™”, wait/notify ์ง€์›
  • ์ž๋ฐ” 5 โ†’ ๋™์‹œ์„ฑ ์ปฌ๋ ‰์…˜์ธ java.util.concurrent ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ์™€ ์‹คํ–‰์ž(Executor) ํ”„๋ ˆ์ž„์›Œํฌ ์ง€์›
  • ์ž๋ฐ” 7 โ†’ ๊ณ ์„ฑ๋Šฅ ๋ณ‘๋ ฌ ๋ถ„ํ•ด ํ”„๋ ˆ์ž„์›Œํฌ์ธ ํฌํฌ-์กฐ์ธ(fork-join) ํŒจํ‚ค์ง€ ์ถ”๊ฐ€
  • ์ž๋ฐ” 8 โ†’ parallel ๋ฉ”์„œ๋“œ๋งŒ ํ•œ ๋ฒˆ ํ˜ธ์ถœํ•˜๋ฉด ํŒŒ์ดํ”„๋ผ์ธ์„ ๋ณ‘๋ ฌ ์‹คํ–‰ํ•  ์ˆ˜ ์žˆ๋Š” ์ŠคํŠธ๋ฆผ ์ง€์›

๋™์‹œ์„ฑ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์„ ํ•  ๋•Œ๋Š” ์•ˆ์ „์„ฑ(Safety)๊ณผ ์‘๋‹ต๊ฐ€๋Šฅ(liveness) ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๊ธฐ ์œ„ํ•ด ์• ์จ์•ผ ํ•˜๋Š”๋ฐ ๋ณ‘๋ ฌ ์ŠคํŠธ๋ฆผ ํŒŒ์ดํ”„๋ผ์ธ ํ”„๋กœ๊ทธ๋ž˜๋ฐ์—์„œ๋„ ๋‹ค๋ฅผ ๋ฐ” ์—†๋‹ค.

์•„์ดํ…œ 45์—์„œ ๋‹ค๋ฃจ์—ˆ๋˜ ๋ฉ”๋ฅด์„ผ ์†Œ์ˆ˜๋ฅผ ์ƒ์„ฑํ•˜๋Š” ํ”„๋กœ๊ทธ๋žจ์„ ๋‹ค์‹œ ์‚ดํŽด๋ณด์ž. (๋ฉ”๋ฅด์„ผ ์ˆ˜ M(n)์€ 2n -1 ํ˜•ํƒœ์ธ ์ˆซ์ž๋ฅผ ๋งํ•œ๋‹ค. ๋ฉ”๋ฅด์„ผ ์†Œ์ˆ˜๋Š” ๋ฉ”๋ฅด์„ผ ์ˆ˜ ์ค‘ ์†Œ์ˆ˜์ธ ๊ฒƒ๋“ค์„ ๊ฐ€๋ฆฌํ‚จ๋‹ค.)

public static void main(String[] args) {
	primes().map(p -> TWO.pow(p.intValueExact()).subtract(ONE))
                        .parallel()
			.filter(mersenne -> mersenne.isProbablePrime(50))
			.limit(20)
			.forEach(System.out::println);
}

static Stream<BigInteger> primes() {
	return Stream.iterate(TWO, BigInteger::nextProbablePrime);
}

์•ˆํƒ€๊น๊ฒŒ๋„ ์ด ํ”„๋กœ๊ทธ๋žจ์€ ์•„๋ฌด๊ฒƒ๋„ ์ถœ๋ ฅํ•˜์ง€ ๋ชปํ•˜๋ฉด์„œ CPU๋Š” 90%๋‚˜ ์žก์•„๋จน๋Š” ์ƒํƒœ๊ฐ€ ๋ฌดํ•œํžˆ ๊ณ„์†๋œ๋‹ค.

๋ฌด์Šจ ์ผ์ด ๋ฒŒ์–ด์ง„ ๊ฑธ๊นŒ?

ํ”„๋กœ๊ทธ๋žจ์ด ์ด๋ ‡๊ฒŒ ๋Š๋ ค์ง„ ์›์ธ์€ ์‚ฌ์‹ค ์–ด์ด์—†๊ฒŒ๋„ ์ŠคํŠธ๋ฆผ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๊ฐ€ ์ด ํŒŒ์ดํ”„๋ผ์ธ์„ ๋ณ‘๋ ฌํ™”ํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์ฐพ์•„๋‚ด์ง€ ๋ชปํ–ˆ๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค. ํ™˜๊ฒฝ์ด ์•„๋ฌด๋ฆฌ ์ข‹๋”๋ผ๋„ ๋ฐ์ดํ„ฐ ์†Œ์Šค๊ฐ€ Stream.iterate๊ฑฐ๋‚˜ ์ค‘๊ฐ„ ์—ฐ์‚ฐ์œผ๋กœ limit๋ฅผ ์“ฐ๋ฉด ํŒŒ์ดํ”„๋ผ์ธ ๋ณ‘๋ ฌํ™”๋กœ๋Š” ์„ฑ๋Šฅ ๊ฐœ์„ ์„ ๊ธฐ๋Œ€ํ•  ์ˆ˜ ์—†๋‹ค.

์›์†Œ ํ•˜๋‚˜๋ฅผ ๊ณ„์‚ฐํ•˜๋Š” ๋น„์šฉ์ด ๋Œ€๋žต ๊ทธ ์ด์ „๊นŒ์ง€์˜ ์›์†Œ ์ „๋ถ€๋ฅผ ๊ณ„์‚ฐํ•œ ๋น„์šฉ์„ ํ•ฉ์นœ ๊ฒƒ๋งŒํผ ๋“ ๋‹ค๋Š” ๋œป์ด๋‹ค. ์ŠคํŠธ๋ฆผ ํŒŒ์ดํ”„๋ผ์ธ์„ ๋งˆ๊ตฌ์žก์ด๋กœ ๋ณ‘๋ ฌํ™”ํ•˜๋ฉด ์•ˆ ๋œ๋‹ค. ์„ฑ๋Šฅ์ด ์˜คํžˆ๋ ค ๋”์ฐํ•˜๊ฒŒ ๋‚˜๋น ์งˆ ์ˆ˜๋„ ์žˆ๋‹ค.

๋Œ€์ฒด๋กœ ์ŠคํŠธ๋ฆผ์˜ ์†Œ์Šค๊ฐ€ ArrayList, HashMap, HashSet, ConcurrentHashMap์˜ ์ธ์Šคํ„ด์Šค๊ฑฐ๋‚˜ ๋ฐฐ์—ด, int ๋ฒ”์œ„, long ๋ฒ”์œ„์ผ ๋•Œ ๋ณ‘๋ ฌํ™”์˜ ํšจ๊ณผ๊ฐ€ ๊ฐ€์žฅ ์ข‹๋‹ค. ์ด ์ž๋ฃŒ๊ตฌ์กฐ๋“ค์€ ๋ชจ๋‘ ๋ฐ์ดํ„ฐ๋ฅผ ์›ํ•˜๋Š” ํฌ๊ธฐ๋กœ ์ •ํ™•ํ•˜๊ณ  ์†์‰ฝ๊ฒŒ ๋‚˜๋ˆŒ ์ˆ˜ ์žˆ์–ด์„œ ์ผ์„ ๋‹ค์ˆ˜์˜ ์Šค๋ ˆ๋“œ์— ๋ถ„๋ฐฐํ•˜๊ธฐ์— ์ข‹๋‹ค๋Š” ํŠน์ง•์ด ์žˆ๋‹ค. ๋‚˜๋ˆ„๋Š” ์ž‘์—…์€ Spliterator๊ฐ€ ๋‹ด๋‹นํ•˜๋ฉฐ, Spliterator ๊ฐ์ฒด๋Š” Stream์ด๋‚˜ Iterable์˜ spliterator ๋ฉ”์„œ๋“œ๋กœ ์–ป์–ด์˜ฌ ์ˆ˜ ์žˆ๋‹ค.

์ด ์ž๋ฃŒ๊ตฌ์กฐ๋“ค์˜ ๋˜ ๋‹ค๋ฅธ ์ค‘์š”ํ•œ ๊ณตํ†ต์ ์€ ์›์†Œ๋“ค์„ ์ˆœ์ฐจ์ ์œผ๋กœ ์‹คํ–‰ํ•  ๋•Œ์˜ ์ฐธ์กฐ ์ง€์—ญ์„ฑ(locality of reference)์ด ๋›ฐ์–ด๋‚˜๋‹ค๋Š” ๊ฒƒ์ด๋‹ค.

์ฐธ์กฐ ์ง€์—ญ์„ฑ์ด๋ž€? ํ•œ๋ฒˆ ์ฐธ์กฐํ•œ ๋ฐ์ดํ„ฐ๋Š” ๋‹ค์‹œ ์ฐธ์กฐ๋  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’๊ณ  ์ฐธ์กฐ๋œ ๋ฐ์ดํ„ฐ ์ฃผ๋ณ€์˜ ๋ฐ์ดํ„ฐ ์—ญ์‹œ ๊ฐ™์ด ์ฐธ์กฐ๋  ๊ฐ€๋Šฅ์„ฑ์ด ๋†’์€ ์„ฑ์งˆ์ด๋‹ค.

ํ•˜์ง€๋งŒ ์ฐธ์กฐ๋“ค์ด ๊ฐ€๋ฆฌํ‚ค๋Š” ์‹ค์ œ ๊ฐ์ฒด๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์„œ๋กœ ๋–จ์–ด์ ธ ์žˆ์„ ์ˆ˜ ์žˆ๋Š”๋ฐ, ๊ทธ๋Ÿฌ๋ฉด ์ฐธ์กฐ ์ง€์—ญ์„ฑ์ด ๋‚˜๋น ์ง„๋‹ค. ์ฐธ์กฐ ์ง€์—ญ์„ฑ์ด ๋‚ฎ์œผ๋ฉด ์Šค๋ ˆ๋“œ๋Š” ๋ฐ์ดํ„ฐ๊ฐ€ ์ฃผ ๋ฉ”๋ชจ๋ฆฌ์—์„œ ์บ์‹œ ๋ฉ”๋ชจ๋ฆฌ๋กœ ์ „์†ก๋˜์–ด ์˜ค๊ธฐ๋ฅผ ๊ธฐ๋‹ค๋ฆฌ๋ฉฐ ๋Œ€๋ถ€๋ถ„ ์‹œ๊ฐ„์„ ๋ฉํ•˜๋‹ˆ ๋ณด๋‚ด๊ฒŒ ๋œ๋‹ค.

์ฐธ์กฐ ์ง€์—ญ์„ฑ์ด ๊ฐ€์žฅ ๋›ฐ์–ด๋‚œ ์ž๋ฃŒ๊ตฌ์กฐ๋Š” ๊ธฐ๋ณธ ํƒ€์ž…์˜ ๋ฐฐ์—ด์ด๋‹ค. ๊ธฐ๋ณธ ํƒ€์ž… ๋ฐฐ์—ด์—์„œ๋Š” (์ฐธ์กฐ๊ฐ€ ์•„๋‹Œ) ๋ฐ์ดํ„ฐ ์ž์ฒด๊ฐ€ ๋ฉ”๋ชจ๋ฆฌ์— ์—ฐ์†ํ•ด์„œ ์ €์žฅ๋˜๊ธฐ ๋•Œ๋ฌธ์ด๋‹ค.

์ข…๋‹จ ์—ฐ์‚ฐ ์ค‘ ๋ณ‘๋ ฌํ™”์— ๊ฐ€์žฅ ์ ํ•ฉํ•œ ๊ฒƒ์€ ์ถ•์†Œ(reduction)๋‹ค.

(min, max, count, sum), anyMatch, allMatch, noneMatch์ฒ˜๋Ÿผ ์กฐ๊ฑด์— ๋งž์œผ๋ฉด ๋ฐ”๋กœ ๋ฐ˜ํ™˜๋˜๋Š” ๋ฉ”์„œ๋“œ๋„ ๋ณ‘๋ ฌํ™”์— ์ ํ•ฉํ•˜๋‹ค. ๋ฐ˜๋ฉด, ๊ฐ€๋ณ€ ์ถ•์†Œ๋ฅผ ์ˆ˜ํ–‰ํ•˜๋Š” Stream์˜ collect ๋ฉ”์„œ๋“œ๋Š” ๋ณ‘๋ ฌํ™”์— ์ ํ•ฉํ•˜์ง€ ์•Š๋‹ค.

๊ฐ€๋ณ€ ์ถ•์†Œ ๋ฉ”์„œ๋“œ๋ž€? ๊ฒฐ๊ณผ๊ฐ’์„ ๊ฐ€๊ณตํ•˜์—ฌ ์ƒˆ๋กœ์šด ๋ฆฌ์ŠคํŠธ๋กœ ์ถ”์ถœํ•˜๋Š” ๋ฉ”์„œ๋“œ์ด๋‹ค.

List<String> list = Arrays.asList("Mike", "Nicki", "John");
String s = list.stream().collect(StringBuilder::new,
            (sb, s1) -> sb.append(" ").append(s1),
            (sb1, sb2) -> sb1.append(sb2.toString())).toString();
System.out.println(s);

์ง์ ‘ ๊ตฌํ˜„ํ•œ Stream, Iterable, Collection์ด ๋ณ‘๋ ฌํ™”์˜ ์ด์ ์„ ์ œ๋Œ€๋กœ ๋ˆ„๋ฆฌ๊ฒŒ ํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด spliterator ๋ฉ”์„œ๋“œ๋ฅผ ๋ฐ˜๋“œ์‹œ ์žฌ์ •์˜ํ•˜๊ณ  ๊ฒฐ๊ณผ ์ŠคํŠธ๋ฆผ์˜ ๋ณ‘๋ ฌํ™” ์„ฑ๋Šฅ์„ ๊ฐ•๋„ ๋†’๊ฒŒ ํ…Œ์ŠคํŠธํ•˜๋ผ.

์ŠคํŠธ๋ฆผ์„ ์ž˜๋ชป ๋ณ‘๋ ฌํ™”ํ•˜๋ฉด (์‘๋‹ต ๋ถˆ๊ฐ€๋ฅผ ํฌํ•จํ•ด) ์„ฑ๋Šฅ์ด ๋‚˜๋น ์งˆ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ ๊ฒฐ๊ณผ ์ž์ฒด๊ฐ€ ์ž˜๋ชป๋˜๊ฑฐ๋‚˜ ์˜ˆ์ƒ ๋ชปํ•œ ๋™์ž‘์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค. ๊ฒฐ๊ณผ๊ฐ€ ์ž˜๋ชป๋˜๊ฑฐ๋‚˜ ์˜ค๋™์ž‘ํ•˜๋Š” ๊ฒƒ์€ ์•ˆ์ „ ์‹คํŒจ(safety failure)๋ผ ํ•œ๋‹ค.

Stream ๋ช…์„ธ๋Š” ์ด๋•Œ ์‚ฌ์šฉ๋˜๋Š” ํ•จ์ˆ˜ ๊ฐ์ฒด์— ๊ด€ํ•œ ์—„์ค‘ํ•œ ๊ทœ์•ฝ์„ ์ •์˜ํ•ด๋†จ๋‹ค. ์˜ˆ์ปจ๋Œ€ Stream์˜ reduce ์—ฐ์‚ฐ์— ๊ฑด๋„ค์ง€๋Š” accumulator(๋ˆ„์ ๊ธฐ)์™€ combiner(๊ฒฐํ•ฉ๊ธฐ) ํ•จ์ˆ˜๋Š” ๋ฐ˜๋“œ์‹œ ๊ฒฐํ•ฉ ๋ฒ•์น™์„ ๋งŒ์กฑํ•˜๊ณ (associative), ๊ฐ„์„ญ๋ฐ›์ง€ ์•Š๊ณ (non-interfeing), ์ƒํƒœ๋ฅผ ๊ฐ–์ง€ ์•Š์•„์•ผ(stateless) ํ•œ๋‹ค

์ถœ๋ ฅ ์ˆœ์„œ๋ฅผ ์ˆœ์ฐจ ๋ฒ„์ „์ฒ˜๋Ÿผ ์ •๋ ฌํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด ์ข…๋‹จ ์—ฐ์‚ฐ forEach๋ฅผ forEachOrdered๋กœ ๋ฐ”๊ฟ”์ฃผ๋ฉด ๋œ๋‹ค.

์‹ฌ์ง€์–ด ๋ฐ์ดํ„ฐ ์†Œ์Šค ์ŠคํŠธ๋ฆผ์ด ํšจ์œจ์ ์œผ๋กœ ๋‚˜๋ˆ ์ง€๊ณ , ๋ณ‘๋ ฌํ™”ํ•˜๊ฑฐ๋‚˜ ๋นจ๋ฆฌ ๋๋‚˜๋Š” ์ข…๋‹จ ์—ฐ์‚ฐ์„ ์‚ฌ์šฉํ•˜๊ณ , ํ•จ์ˆ˜ ๊ฐ์ฒด๋“ค๋„ ๊ฐ„์„ญํ•˜์ง€ ์•Š๋”๋ผ๋„ ํŒŒ์ดํ”„๋ผ์ธ์ด ์ˆ˜ํ–‰ํ•˜๋Š” ์ง„์งœ ์ž‘์—…์ด ๋ณ‘๋ ฌํ™”์— ๋“œ๋Š” ์ถ”๊ฐ€ ๋น„์šฉ์„ ์ƒ์‡„ํ•˜์ง€ ๋ชปํ•œ๋‹ค๋ฉด ์„ฑ๋Šฅ ํ–ฅ์ƒ์€ ๋ฏธ๋ฏธํ•  ์ˆ˜ ์žˆ๋‹ค.

์ŠคํŠธ๋ฆผ ๋ณ‘๋ ฌํ™”๋Š” ์˜ค์ง ์„ฑ๋Šฅ ์ตœ์ ํ™” ์ˆ˜๋‹จ์ž„์„ ๊ธฐ์–ตํ•ด์•ผ ํ•œ๋‹ค. ๋‹ค๋ฅธ ์ตœ์ ํ™”์™€ ๋งˆ์ฐฌ๊ฐ€์ง€๋กœ ๋ณ€๊ฒฝ ์ „ํ›„๋กœ ๋ฐ˜๋“œ์‹œ ์„ฑ๋Šฅ์„ ํ…Œ์ŠคํŠธํ•˜์—ฌ ๋ณ‘๋ ฌํ™”๋ฅผ ์‚ฌ์šฉํ•  ๊ฐ€์น˜๊ฐ€ ์žˆ๋Š”์ง€ ํ™•์ธํ•ด์•ผ ํ•œ๋‹ค. (์•„์ดํ…œ 67)

์กฐ๊ฑด์ด ์ž˜ ๊ฐ–์ถฐ์ง€๋ฉด parallel ๋ฉ”์„œ๋“œ ํ˜ธ์ถœ ํ•˜๋‚˜๋กœ ๊ฑฐ์˜ ํ”„๋กœ์„ธ์„œ ์ฝ”์–ด ์ˆ˜์— ๋น„๋ก€ํ•˜๋Š” ์„ฑ๋Šฅ ํ–ฅ์ƒ์„ ๋งŒ๋ฝํ•  ์ˆ˜ ์žˆ๋‹ค.

static long pi(long n) {
	return LongStream.rangeClosed(2, n)
		.parallel()
		.mapToObj(BigInteger::valueOf)
		.filter(i -> i.isProbablePrime(50))
		.count();
}

๋ฌด์ž‘์œ„ ์ˆ˜๋“ค๋กœ ์ด๋ค„์ง„ ์ŠคํŠธ๋ฆผ์„ ๋ณ‘๋ ฌํ™”ํ•˜๋ ค๊ฑฐ๋“  TreadLocalRandom(ํ˜น์€ ๊ตฌ์‹์ธ Random)๋ณด๋‹ค๋Š” SplittableRandom ์ธ์Šคํ„ด์Šค๋ฅผ ์ด์šฉํ•˜์ž

์ •๋ฆฌ

๊ณ„์‚ฐ๋„ ์˜ฌ๋ฐ”๋กœ ์ˆ˜ํ–‰ํ•˜๊ณ  ์„ฑ๋Šฅ๋„ ๋นจ๋ผ์งˆ ๊ฑฐ๋ผ๋Š” ํ™•์‹  ์—†์ด๋Š” ์ŠคํŠธ๋ฆผ ํŒŒ์ดํ”„๋ผ์ธ ๋ณ‘๋ ฌํ™”๋Š” ์‹œ๋„์กฐ์ฐจ ํ•˜์ง€ ๋ง๋ผ. ์ŠคํŠธ๋ฆผ์„ ์ž˜๋ชป ๋ณ‘๋ ฌํ™”ํ•˜๋ฉด ํ”„๋กœ๊ทธ๋žจ์„ ์˜ค๋™์ž‘ํ•˜๊ฒŒ ํ•˜๊ฑฐ๋‚˜ ์„ฑ๋Šฅ์„ ๊ธ‰๊ฒฉํžˆ ๋–จ์–ด๋œจ๋ฆฐ๋‹ค. ๋ณ‘๋ ฌํ™”ํ•˜๋Š” ํŽธ์ด ๋‚ซ๋‹ค๊ณ  ๋ฏฟ๋”๋ผ๋„, ์ˆ˜์ • ํ›„์˜ ์ฝ”๋“œ๊ฐ€ ์—ฌ์ „ํžˆ ์ •ํ™•ํ•œ์ง€ ํ™•์ธํ•˜๊ณ  ์šด์˜ ํ™˜๊ฒฝ๊ณผ ์œ ์‚ฌํ•œ ์กฐ๊ฑด์—์„œ ์ˆ˜ํ–‰ํ•ด๋ณด๋ฉฐ ์„ฑ๋Šฅ์ง€ํ‘œ๋ฅผ ์œ ์‹ฌํžˆ ๊ด€์ฐฐํ•˜๋ผ. ๊ทธ๋ž˜์„œ ๊ณ„์‚ฐ๋„ ์ •ํ™•ํ•˜๊ณ  ์„ฑ๋Šฅ๋„ ์ข‹์•„์กŒ์Œ์ด ํ™•์‹คํ•ด์กŒ์„ ๋•Œ ์˜ค์ง ๊ทธ๋Ÿด ๋•Œ๋งŒ ๋ณ‘๋ ฌํ™” ๋ฒ„์ „ ์ฝ”๋“œ๋ฅผ ์šด์˜ ์ฝ”๋“œ์— ๋ฐ˜์˜ํ•ด๋ผ

์ฐธ์กฐ์ž๋ฃŒ

http://www.nextree.co.kr/p6506/

โš ๏ธ **GitHub.com Fallback** โš ๏ธ