-
Notifications
You must be signed in to change notification settings - Fork 0
5주차: 싱글톤 패턴 #5
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
5주차: 싱글톤 패턴 #5
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,7 @@ | ||
| package singleton; | ||
|
|
||
| public class SingletonPattern { | ||
| public static void main(String[] args) { | ||
|
|
||
| } | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| package singleton.boiler; | ||
|
|
||
| /** | ||
| * enum으로 싱글톤을 생성하면 | ||
| * 동기화 문제, 클래스 로딩 문제, 리플렉션, 직렬화, 역직렬화 문제를 해결할 수 있다. | ||
| */ | ||
| public enum ChocolateBoilerEnum { | ||
| UNIQUE_INSTANCE; | ||
|
|
||
| private boolean empty; | ||
| private boolean boiled; | ||
|
|
||
| /** | ||
| * 보일러가 비어있을 경우에만 재료를 넣는다 | ||
| */ | ||
| public void fill() { | ||
| if (isEmpty()) { | ||
| empty = false; | ||
| boiled = false; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * 보일러가 가득차있고, 다 끓여진 상태에서만 초콜릿을 흘려보낸다 | ||
| */ | ||
| public void drain() { | ||
| if (!isEmpty() && isBoiled()) { | ||
| empty = true; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * 보일러가 가득차있고, 아직 끓지않은 상태에서만 끓인다 | ||
| */ | ||
| public void boil() { | ||
| if (!isEmpty() && !isBoiled()) { | ||
| boiled = true; | ||
| } | ||
| } | ||
|
|
||
| public boolean isEmpty() { | ||
| return empty; | ||
| } | ||
|
|
||
| public boolean isBoiled() { | ||
| return boiled; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,56 @@ | ||
| package singleton.boiler; | ||
|
|
||
| /** | ||
| * public static final field | ||
| */ | ||
| public class ChocolateBoilerFinal { | ||
| private boolean empty; | ||
| private boolean boiled; | ||
|
|
||
| // 싱글톤 인스턴스를 처음부터 초기화한다. | ||
| private static final ChocolateBoilerFinal uniqueInstance = new ChocolateBoilerFinal(); | ||
|
|
||
| private ChocolateBoilerFinal() { | ||
| empty = true; | ||
| boiled = false; // 보일러가 비어있을 때만 돌아간다 | ||
| } | ||
|
|
||
| public static ChocolateBoilerFinal getInstance() { | ||
| return uniqueInstance; | ||
| } | ||
|
|
||
|
Comment on lines
+3
to
+21
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
| /** | ||
| * 보일러가 비어있을 경우에만 재료를 넣는다 | ||
| */ | ||
| public void fill() { | ||
| if (isEmpty()) { | ||
| empty = false; | ||
| boiled = false; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * 보일러가 가득차있고, 다 끓여진 상태에서만 초콜릿을 흘려보낸다 | ||
| */ | ||
| public void drain() { | ||
| if (!isEmpty() && isBoiled()) { | ||
| empty = true; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * 보일러가 가득차있고, 아직 끓지않은 상태에서만 끓인다 | ||
| */ | ||
| public void boil() { | ||
| if (!isEmpty() && !isBoiled()) { | ||
| boiled = true; | ||
| } | ||
| } | ||
| public boolean isEmpty() { | ||
| return empty; | ||
| } | ||
|
|
||
| public boolean isBoiled() { | ||
| return boiled; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,59 @@ | ||
| package singleton.boiler; | ||
|
|
||
| /** | ||
| * lazy initialization -> 동기화 문제 | ||
| */ | ||
| public class ChocolateBoilerLazy { | ||
| private boolean empty; | ||
| private boolean boiled; | ||
|
|
||
| private static ChocolateBoilerLazy uniqueInstance; | ||
|
|
||
| private ChocolateBoilerLazy() { | ||
| empty = true; | ||
| boiled = false; // 보일러가 비어있을 때만 돌아간다 | ||
| } | ||
|
|
||
| public static ChocolateBoilerLazy getInstance() { | ||
| if (uniqueInstance == null) { // 멀티 스레딩 환경에서 최초로 인스턴스가 생성될 시점에 동기화 문제 발생 | ||
| uniqueInstance = new ChocolateBoilerLazy(); | ||
| } | ||
|
|
||
| return uniqueInstance; | ||
| } | ||
|
Comment on lines
+3
to
+23
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
|
||
|
|
||
| /** | ||
| * 보일러가 비어있을 경우에만 재료를 넣는다 | ||
| */ | ||
| public void fill() { | ||
| if (isEmpty()) { | ||
| empty = false; | ||
| boiled = false; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * 보일러가 가득차있고, 다 끓여진 상태에서만 초콜릿을 흘려보낸다 | ||
| */ | ||
| public void drain() { | ||
| if (!isEmpty() && isBoiled()) { | ||
| empty = true; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * 보일러가 가득차있고, 아직 끓지않은 상태에서만 끓인다 | ||
| */ | ||
| public void boil() { | ||
| if (!isEmpty() && !isBoiled()) { | ||
| boiled = true; | ||
| } | ||
| } | ||
| public boolean isEmpty() { | ||
| return empty; | ||
| } | ||
|
|
||
| public boolean isBoiled() { | ||
| return boiled; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,61 @@ | ||
| package singleton.boiler; | ||
|
|
||
| /** | ||
| * lazy initialization & synchronized | ||
| */ | ||
| public class ChocolateBoilerSynchronized { | ||
| private boolean empty; | ||
| private boolean boiled; | ||
|
|
||
| private static ChocolateBoilerSynchronized uniqueInstance; | ||
|
|
||
| private ChocolateBoilerSynchronized() { | ||
| empty = true; | ||
| boiled = false; // 보일러가 비어있을 때만 돌아간다 | ||
| } | ||
|
|
||
| // 인스턴스가 최초로 초기화 되는 시점에만 동기화가 필요하지만, | ||
| // 이 방식은 항상 동기화가 일어나 속도 문제가 있다. | ||
| public static synchronized ChocolateBoilerSynchronized getInstance() { | ||
| if (uniqueInstance == null) { | ||
| uniqueInstance = new ChocolateBoilerSynchronized(); | ||
| } | ||
|
|
||
| return uniqueInstance; | ||
| } | ||
|
Comment on lines
+3
to
+25
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
하지만 속도 문제가 존재한다. |
||
|
|
||
| /** | ||
| * 보일러가 비어있을 경우에만 재료를 넣는다 | ||
| */ | ||
| public void fill() { | ||
| if (isEmpty()) { | ||
| empty = false; | ||
| boiled = false; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * 보일러가 가득차있고, 다 끓여진 상태에서만 초콜릿을 흘려보낸다 | ||
| */ | ||
| public void drain() { | ||
| if (!isEmpty() && isBoiled()) { | ||
| empty = true; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * 보일러가 가득차있고, 아직 끓지않은 상태에서만 끓인다 | ||
| */ | ||
| public void boil() { | ||
| if (!isEmpty() && !isBoiled()) { | ||
| boiled = true; | ||
| } | ||
| } | ||
| public boolean isEmpty() { | ||
| return empty; | ||
| } | ||
|
|
||
| public boolean isBoiled() { | ||
| return boiled; | ||
| } | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,65 @@ | ||
| package singleton.boiler; | ||
|
|
||
| /** | ||
| * lazy initialization & volatile | ||
| */ | ||
| public class ChocolateBoilerVolatile { | ||
| private boolean empty; | ||
| private boolean boiled; | ||
|
|
||
| private volatile static ChocolateBoilerVolatile uniqueInstance; | ||
|
|
||
| private ChocolateBoilerVolatile() { | ||
| empty = true; | ||
| boiled = false; // 보일러가 비어있을 때만 돌아간다 | ||
| } | ||
|
|
||
| public static ChocolateBoilerVolatile getInstance() { | ||
| if (uniqueInstance == null) { | ||
| // 인스턴스가 최초로 초기화되는 시점에만 동기화가 일어난다. | ||
| // 다만 java 5 버전 이하의 JVM에서는 volatile 키워드가 제대로 동작하지 않는 이슈가 있다. | ||
| synchronized (ChocolateBoilerVolatile.class) { | ||
| if (uniqueInstance == null) { | ||
| uniqueInstance = new ChocolateBoilerVolatile(); | ||
| } | ||
| } | ||
| } | ||
|
|
||
| return uniqueInstance; | ||
| } | ||
|
|
||
|
Comment on lines
+2
to
+30
Member
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
다만 java5 버전 이하에서는 volatile 키워드가 제대로 동작하지 않는 이슈가 있다 |
||
| /** | ||
| * 보일러가 비어있을 경우에만 재료를 넣는다 | ||
| */ | ||
| public void fill() { | ||
| if (isEmpty()) { | ||
| empty = false; | ||
| boiled = false; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * 보일러가 가득차있고, 다 끓여진 상태에서만 초콜릿을 흘려보낸다 | ||
| */ | ||
| public void drain() { | ||
| if (!isEmpty() && isBoiled()) { | ||
| empty = true; | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * 보일러가 가득차있고, 아직 끓지않은 상태에서만 끓인다 | ||
| */ | ||
| public void boil() { | ||
| if (!isEmpty() && !isBoiled()) { | ||
| boiled = true; | ||
| } | ||
| } | ||
| public boolean isEmpty() { | ||
| return empty; | ||
| } | ||
|
|
||
| public boolean isBoiled() { | ||
| return boiled; | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
동기화 문제, 클래스 로딩 문제, 리플렉션, 직렬화, 역직렬화 문제를 해결할 수 있다.