item83 SeungminLee - JAVA-JIKIMI/EFFECTIVE-JAVA3 GitHub Wiki

item 83

์ง€์—ฐ ์ดˆ๊ธฐํ™”๋Š” ์‹ ์ค‘ํžˆ ์‚ฌ์šฉํ•˜๋ผ

  • ์ง€์—ฐ์ดˆ๊ธฐํ™”๋Š” ํ•„๋“œ์˜ ์ดˆ๊ธฐํ™” ์‹œ์ ์„ ๊ทธ ๊ฐ’์ด ์ฒ˜์Œ ํ•„์š”ํ•  ๋•Œ๊นŒ์ง€ ๋Šฆ์ถ”๋Š” ๊ธฐ๋ฒ•
  • ๊ฐ’์ด ์ „ํ˜€ ์“ฐ์ด์ง€ ์•Š์œผ๋ฉด ์ดˆ๊ธฐํ™”๋„ ๊ฒฐ์ฝ” ์ผ์–ด๋‚˜์ง€ ์•Š์Œ
  • ์ด ๊ธฐ๋ฒ•์€ ์ •์  ํ•„๋“œ์™€ ์ธ์Šคํ„ด์Šค ํ•„๋“œ ๋ชจ๋‘์— ์‚ฌ์šฉ ๊ฐ€๋Šฅ
  • ์ฃผ๋กœ ์ตœ์ ํ™” ์šฉ๋„๋กœ ์‚ฌ์šฉํ•˜์ง€๋งŒ, ํด๋ž˜์Šค์™€ ์ธ์Šคํ„ด์Šค ์ดˆ๊ธฐํ™” ๋•Œ ๋ฐœ์ƒํ•˜๋Š” ์œ„ํ—˜ํ•œ ์ˆœํ™˜ ๋ฌธ์ œ๋ฅผ ํ•ด๊ฒฐํ•  ์ˆ˜ ์žˆ์Œ

lazy initalization /lazy loading /lazy evaluation

์ง€์—ฐ ์ดˆ๊ธฐํ™”๋ฅผ ์œ„ํ•œ ์ตœ์„ ์˜ ์กฐ์–ธ "ํ•„์š”ํ•  ๋•Œ๊นŒ์ง€๋Š” ํ•˜์ง€ ๋ง๋ผ"

์ง€์—ฐ ์ดˆ๊ธฐํ™”๋Š” ์–‘๋‚ ์˜ ๊ฒ€์ด๋‹ค. ํด๋ž˜์Šค ํ˜น์€ ์ธ์Šคํ„ด์Šค ์ƒ์„ฑ ์‹œ์˜ ์ดˆ๊ธฐํ™” ๋น„์šฉ์€ ์ค„์ง€๋งŒ ๊ทธ ๋Œ€์‹  ์ง€์—ฐ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ํ•„๋“œ์— ์ ‘๊ทผํ•˜๋Š” ๋น„์šฉ์€ ์ปค์ง„๋‹ค.

โ†’ ํ•„๋“œ๋“ค ์ค‘ ์ดˆ๊ธฐํ™”๊ฐ€ ์ด๋ค„์ง€๋Š” ๋น„์œจ์— ๋”ฐ๋ผ โ†’ ์‹ค์ œ ์ดˆ๊ธฐํ™”์— ๋“œ๋Š” ๋น„์šฉ์— ๋”ฐ๋ผ โ†’ ์ดˆ๊ธฐํ™”๋œ ๊ฐ ํ•„๋“œ๋ฅผ ์–ผ๋งˆ๋‚˜ ๋นˆ๋ฒˆํžˆ ํ˜ธ์ถœํ•˜๋‚˜ ์— ๋”ฐ๋ผ ์ง€์—ฐ์ดˆ๊ธฐํ™”๊ฐ€ ์‹ค์ œ๋กœ๋Š” ์„ฑ๋Šฅ์„ ๋А๋ ค์ง€๊ฒŒ ํ•  ์ˆ˜๋„ ์žˆ๋‹ค.

ํด๋ž˜์Šค์˜ ์ธ์Šคํ„ด์Šค ์ค‘ ๊ทธ ํ•„๋“œ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” ์ธ์Šคํ„ด์Šค์˜ ๋น„์œจ์ด ๋‚ฎ์€ ๋ฐ˜๋ฉด, ๊ทธ ํ•„๋“œ๋ฅผ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ๋น„์šฉ์ด ํฌ๋‹ค๋ฉด ์ง€์—ฐ ์ดˆ๊ธฐํ™”๊ฐ€ ์ œ ์—ญํ• ์„ ํ•ด์ค„ ๊ฒƒ์ด๋‹ค. (์ง€์—ฐ์ดˆ๊ธฐํ™”๊ฐ€ ํšจ๊ณผ๊ฐ€ ์žˆ๋Š”์ง€ ์•Œ์•„๋ณด๊ธฐ ์œ„ํ•ด์„œ๋Š” ์ ์šฉ ์ „ํ›„์˜ ์„ฑ๋Šฅ์„ ์ธก์ •ํ•˜๋Š” ๊ธธ ๋ฟ์ด๋‹ค)

๋ฉ€ํ‹ฐ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ์˜ ์ง€์—ฐ ์ดˆ๊ธฐํ™”

๋ฉ€ํ‹ฐ ์Šค๋ ˆ๋“œ ํ™˜๊ฒฝ์—์„œ์˜ ์ง€์—ฐ ์ดˆ๊ธฐํ™”๋Š” ๊นŒ๋‹ค๋กญ๋‹ค. ์ง€์—ฐ ์ดˆ๊ธฐํ™”ํ•˜๋Š” ํ•„๋“œ๋ฅผ ๋‘˜ ์ด์ƒ์˜ ์Šค๋ ˆ๋“œ๊ฐ€ ๊ณต์œ ํ•œ๋‹ค๋ฉด ์–ด๋–ค ํ˜•ํƒœ๊ณ ๋“  ๋ฐ˜๋“œ์‹œ ๋™๊ธฐํ™” ํ•ด์•ผ ํ•œ๋‹ค. ์ด๋ฅผ ์–ด๊ธธ์‹œ ์‹ฌ๊ฐํ•œ ๋ฒ„๊ทธ๋ฅผ ์ดˆ๋ž˜ํ•œ๋‹ค. ๋Œ€๋ถ€๋ถ„์˜ ์ƒํ™ฉ์—์„œ ์ผ๋ฐ˜์ ์ธ ์ดˆ๊ธฐํ™”๊ฐ€ ์ง€์—ฐ ์ดˆ๊ธฐํ™” ๋ณด๋‹ค ๋‚ซ๋‹ค๋Š” ๊ฒƒ์„ ๊ธฐ์–ตํ•˜๊ณ  ์˜ˆ์ œ๋ฅผ ๋ณด๋„๋ก ํ•˜์ž.

์ผ๋ฐ˜์ ์ธ ์ธ์Šคํ„ด์Šค ํ•„๋“œ๋ฅผ ์„ ์–ธํ•  ๋•Œ ์ดˆ๊ธฐํ™”๋ฅผ ํ•˜๋Š” ์˜ˆ์ œ

private final FieldType field = computeFieldValue();

์ง€์—ฐ์ดˆ๊ธฐํ™”๋กœ ์ธํ•ด ์ดˆ๊ธฐํ™” ์ˆœํ™˜์„ฑ(initalization circularity)๊ฐ€ ๊นจ์งˆ ๊ฒƒ ๊ฐ™์œผ๋ฉด synchronized ๋ฅผ ์‚ฌ์šฉํ•˜์ž. (์ดˆ๊ธฐํ™” ์ˆœํ™˜์„ฑ์ด ๊นจ์ง„ ์˜ˆ: class A ์˜ ์ƒ์„ฑ์ž๋Š” class B ์ธ์Šคํ„ด์Šค๊ฐ€ ํ•„์š”ํ•˜๊ณ  class B ์ƒ์„ฑ์ž๋Š” class C ์ธ์Šคํ„ด์Šค๊ฐ€ ํ•„์š”ํ•˜๊ณ  class C ์ƒ์„ฑ์ž๋Š” class A ์ธ์Šคํ„ด์Šค๊ฐ€ ํ•„์š”ํ•˜๋‹ค)

private FieldType field;

private synchronized FieldType getField() {
	if (field == null)
		field = computeFieldValue();
	return field;
}

์ •์ ํ•„๋“œ๋„ ํ•„๋“œ์™€ ๋ฉ”์„œ๋“œ ์„ ์–ธ์— static ์„ ์„ ์–ธํ•˜๋ฉด ๋˜‘๊ฐ™์ด ์ผ๋ฐ˜ ์ดˆ๊ธฐํ™”์™€ sunchronized๋ฅผ ์‚ฌ์šฉํ•œ ์ดˆ๊ธฐํ™”๋ฅผ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์ง€๋งŒ ์„ฑ๋Šฅ์„ ๊ณ ๋ คํ•œ ๋” ์„ธ๋ จ๋œ ๋ฐฉ๋ฒ•์ด ์žˆ๋‹ค.

์ •์ ํ•„๋“œ ์ง€์—ฐ์ดˆ๊ธฐํ™”์—๋Š” ์ง€์—ฐ ์ดˆ๊ธฐํ™” ํ™€๋” ๊ด€์šฉ๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜์ž.

private static class FieldHolder {
	static final FieldType field = computeFieldValue();
}

private static FieldType getField() { return FieldHolder.field; }
  • getField๊ฐ€ ์ฒ˜์Œ ํ˜ธ์ถœ๋˜๋Š” ์ˆœ๊ฐ„ FieldHolder.field๊ฐ€ ์ฒ˜์Œ ์ฝํžˆ๋ฉด์„œ FieldHolder ํด๋ž˜์Šค ์ดˆ๊ธฐํ™”๋ฅผ ์ด‰๋ฐœํ•œ๋‹ค.
  • ๋ฉ‹์ง„ ์ : getField ๋ฉ”์„œ๋“œ๊ฐ€ ํ•„๋“œ์— ์ ‘๊ทผํ•˜๋ฉด์„œ ๋™๊ธฐํ™”๋ฅผ ์ „ํ˜€ ํ•˜์ง€ ์•Š์œผ๋‹ˆ ์„ฑ๋Šฅ์ด ๋А๋ ค์งˆ ๊ฑฐ๋ฆฌ๊ฐ€ ์ „ํ˜€ ์—†๋‹ค!
  • ์ผ๋ฐ˜์ ์ธ VM์€ ์˜ค์ง ํด๋ž˜์Šค๋ฅผ ์ดˆ๊ธฐํ™”ํ•  ๋•Œ๋งŒ ํ•„๋“œ ์ ‘๊ทผ์„ ๋™๊ธฐํ™” ํ•œ๋‹ค โ†’ ์ดˆ๊ธฐํ™”๊ฐ€ ๋๋‚œ ํ›„์—๋Š” VM์ด ๋™๊ธฐํ™” ์ฝ”๋“œ๋ฅผ ์ œ๊ฑฐํ•œ๋‹ค โ†’ ์ดํ›„ ์•„๋ฌด๋Ÿฐ ๊ฒ€์‚ฌ๋‚˜ ๋™๊ธฐํ™” ์—†์ด ํ•„๋“œ์— ์ ‘๊ทผํ•˜๊ฒŒ ๋œ๋‹ค.

์„ฑ๋Šฅ ๋•Œ๋ฌธ์— ์ธ์Šคํ„ด์Šค ํ•„๋“œ๋ฅผ ์ง€์—ฐ ์ดˆ๊ธฐํ™”ํ•ด์•ผ ํ•œ๋‹ค๋ฉด ์ด์ค‘๊ฒ€์‚ฌ ๊ด€์šฉ๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜๋ผ

์ด ๊ด€์šฉ๊ตฌ๋Š” ์ดˆ๊ธฐํ™”๋œ ํ•„๋“œ์— ์ ‘๊ทผํ•  ๋•Œ์˜ ๋™๊ธฐํ™” ๋น„์šฉ์„ ์—†์• ์ค€๋‹ค. ํ•„๋“œ์˜ ๊ฐ’์„ ๋‘ ๋ฒˆ ๊ฒ€์‚ฌํ•˜๋Š” ๋ฐฉ์‹์œผ๋กœ, ํ•œ ๋ฒˆ์€ ๋™๊ธฐํ™” ์—†์ด ๊ฒ€์‚ฌํ•˜๊ณ  (ํ•„๋“œ๊ฐ€ ์•„์ง ์ดˆ๊ธฐํ™” ๋˜์ง€ ์•Š์•˜๋‹ค๋ฉด) ๋‘ ๋ฒˆ์งธ๋Š” ๋™๊ธฐํ™”ํ•˜์—ฌ ๊ฒ€์‚ฌํ•œ๋‹ค. ๋‘ ๋ฒˆ์งธ ๊ฒ€์‚ฌ์—์„œ๋„ ํ•„๋“œ๊ฐ€ ์ดˆ๊ธฐํ™”๋˜์ง€ ์•Š์•˜์„ ๋•Œ๋งŒ ํ•„๋“œ๋ฅผ ์ดˆ๊ธฐํ™”ํ•œ๋‹ค.

โ†’ ํ•„๋“œ๊ฐ€ ์ดˆ๊ธฐํ™”๋œ ํ›„๋กœ๋Š” ๋™๊ธฐํ™”ํ•˜์ง€ ์•Š์œผ๋ฏ€๋กœ ํ•ด๋‹น ํ•„๋“œ๋Š” ๋ฐ˜๋“œ์‹œ volatile๋กœ ์„ ์–ธํ•ด์•ผ ํ•œ๋‹ค.

private volatile FieldType field;

private FieldType getField() {
	FieldType result = field;
	if (result != null )  // ์ฒซ ๋ฒˆ์งธ ๊ฒ€์‚ฌ (๋ฝ X)
		return result;

	synchronized(this) {
		if (field == null) // ๋‘ ๋ฒˆ์งธ ๊ฒ€์‚ฌ (๋ฝ O)
			field = computeFieldValue();
		return field;
	}
}
  • result ์ง€์—ญ๋ณ€์ˆ˜๊ฐ€ ํ•„์š”ํ•œ ์ด์œ ๋Š” ๋ฌด์—‡์ธ๊ฐ€? ์ด ๋ณ€์ˆ˜๊ฐ€ ์ด๋ฏธ ์ดˆ๊ธฐํ™”๋œ ์ผ๋ฐ˜์ ์ธ ์ƒํ™ฉ์—์„œ ๊ทธ ํ•„๋“œ๋ฅผ ๋”ฑ ํ•œ ๋ฒˆ๋งŒ ์ฝ๋„๋ก ๋ณด์žฅํ•˜๋Š” ์—ญํ• ์„ ํ•œ๋‹ค. ๋ฐ˜๋“œ์‹œ ํ•„์š”ํ•˜์ง€๋Š” ์•Š์ง€๋งŒ ์„ฑ๋Šฅ์„ ๋†’์—ฌ์ฃผ๋Š” ์šฐ์•„ํ•œ ๋ฐฉ๋ฒ•์ด๋‹ค.
  • ์ด์ค‘๊ฒ€์‚ฌ ๊ด€์šฉ๊ตฌ๋ฅผ ์ •์  ํ•„๋“œ์—๋„ ์ ์šฉํ•  ์ˆ˜ ์žˆ์œผ๋‚˜ ์ง€์—ฐ ์ดˆ๊ธฐํ™” ํ™€๋” ๊ด€์šฉ๊ตฌ๊ฐ€ ๋” ๋‚ซ๋‹ค.
  • ๋ณ€์ข…: ๋•Œ๋•Œ๋กœ ๋ฐ˜๋ณตํ•ด์„œ ์ดˆ๊ธฐํ™”ํ•ด๋„ ์ƒ๊ด€์—†๋Š” ์ธ์Šคํ„ด์Šค ํ•„๋“œ๋ฅผ ์ง€์—ฐ ์ดˆ๊ธฐํ™”ํ•ด์•ผ ํ•œ๋‹ค๋ฉด ๋‘ ๋ฒˆ์งธ ๊ฒ€์‚ฌ๋ฅผ ์ƒ๋žตํ•  ์ˆ˜ ์žˆ๋‹ค. (๋‹จ์ผ ๊ฒ€์‚ฌ ๊ด€์šฉ๊ตฌ)

๋‹จ์ผ ๊ฒ€์‚ฌ ๊ด€์šฉ๊ตฌ

private volatile FieldType field;

private FieldType getField() {
	FieldType result = field;
	if (result == null) 
		field = result = computeFieldValue();
	return result;
}

  • ์ด๋ฒˆ ์•„์ดํ…œ์—์„œ ์ด์•ผ๊ธฐํ•œ ๋ชจ๋“  ์ดˆ๊ธฐํ™” ๊ธฐ๋ฒ•์€ ๊ธฐ๋ณธ ํƒ€์ž… ํ•„๋“œ์™€ ๊ฐ์ฒด ์ฐธ์กฐ ํ•„๋“œ ๋ชจ๋‘์— ์ ์šฉํ•  ์ˆ˜ ์žˆ๋‹ค. ์ด์ค‘๊ฒ€์‚ฌ์™€ ๋‹จ์ผ๊ฒ€์‚ฌ ๊ด€์šฉ๊ตฌ๋ฅผ ์ˆ˜์น˜ ๊ธฐ๋ณธ ํƒ€์ž… ํ•„๋“œ์— ์ ์šฉํ•œ๋‹ค๋ฉด ํ•„๋“œ์˜ ๊ฐ’์„ null ๋Œ€์‹  (์ˆซ์ž ๊ธฐ๋ณธ ํƒ€์ž… ๋ณ€์ˆ˜์˜ ๊ธฐ๋ณธ๊ฐ’์ธ) 0๊ณผ ๋น„๊ตํ•˜๋ฉด ๋œ๋‹ค.

  • ๋ชจ๋“  ์Šค๋ ˆ๋“œ๊ฐ€ ํ•„๋“œ์˜ ๊ฐ’์„ ๋‹ค์‹œ ๊ณ„์‚ฐํ•ด๋„ ์ƒ๊ด€์—†๊ณ  ํ•„๋“œ์˜ ํƒ€์ž…์ด long๊ณผ double์„ ์ œ์™ธํ•œ ๋‹ค๋ฅธ ๊ธฐ๋ณธ ํƒ€์ž…์ด๋ผ๋ฉด ๋‹จ์ผ๊ฒ€์‚ฌ์˜ ํ•„๋“œ ์„ ์–ธ์—์„œ volatile์„ ์—†์• ๋„ ๋œ๋‹ค. (racy single-check)

    (long ๊ณผ double์€ ๊ผญ volatile์„ ์จ์•ผ ํ•˜๋Š” ์ด์œ : ํ•œ๋ฒˆ์— 32bits์”ฉ ์ฝ๊ณ  ์“ฐ๋Š”๋ฐ long๊ณผ double์€ 8byte ๋ผ์„œ 32 bits๋Š” ํ•œ ์“ฐ๋ ˆ๋“œ์—, ๋‚˜๋จธ์ง€ 32bits ๋Š” ๋‹ค๋ฅธ ์“ฐ๋ ˆ๋“œ์— ์จ์งˆ ์ˆ˜ ์žˆ๋‹ค. (word taering)

  • racy single-check ์€ ์–ด๋–ค ํ™˜๊ฒฝ์—์„œ๋Š” ํ•„๋“œ ์ ‘๊ทผ ์†๋„๋ฅผ ๋†’์—ฌ์ฃผ์ง€๋งŒ, ์ดˆ๊ธฐํ™”๊ฐ€ ์Šค๋ ˆ๋“œ๋‹น ์ตœ๋Œ€ ํ•œ ๋ฒˆ ๋” ์ด๋ค„์งˆ ์ˆ˜ ์žˆ๋Š” ์•„์ฃผ ์ด๋ก€์ ์ธ ๊ธฐ๋ฒ•์œผ๋กœ, ์ž˜ ์“ฐ์ง€ ์•Š๋Š”๋‹ค.

ํ•ต์‹ฌ ์ •๋ฆฌ

  1. ๋Œ€๋ถ€๋ถ„์˜ ํ•„๋“œ๋Š” ์ง€์—ฐ์‹œํ‚ค์ง€ ๋ง๊ณ  ๊ณง๋ฐ”๋กœ ์ดˆ๊ธฐํ™”ํ•ด์•ผ ํ•œ๋‹ค.
  2. ์„ฑ๋Šฅ ๋•Œ๋ฌธ์— ์ง€์—ฐ์ดˆ๊ธฐํ™”๋ฅผ ๊ผญ ์จ์•ผ ํ•œ๋‹ค๋ฉด ์˜ฌ๋ฐ”๋ฅธ ์ง€์—ฐ ์ดˆ๊ธฐํ™” ๊ธฐ๋ฒ•์„ ์‚ฌ์šฉํ•˜์ž.
  3. ์ธ์Šคํ„ด์Šค ํ•„๋“œ์—๋Š” ์ด์ค‘๊ฒ€์‚ฌ ๊ด€์šฉ๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜์ž.
  4. ์ •์  ํ•„๋“œ์—๋Š” ์ง€์—ฐ ์ดˆ๊ธฐํ™” ํ™€๋” ํด๋ž˜์Šค ๊ด€์šฉ๊ตฌ๋ฅผ ์‚ฌ์šฉํ•˜์ž.
  5. ๋ฐ˜๋ณตํ•ด์„œ ์ดˆ๊ธฐํ™”ํ•ด๋„ ๊ดœ์ฐฎ์€ ์ธ์Šคํ„ด์Šค ํ•„๋“œ์—๋Š” ๋‹จ์ผ ๊ฒ€์‚ฌ ๊ด€์šฉ๊ตฌ ์‚ฌ์šฉ์„ ๊ณ ๋ คํ•ด๋ณด์ž.