1. 예제 프로그램
<Singleton.java>
package ch05.Sample;
//인스턴스가 1개만
public class Singleton {
private static Singleton s = new Singleton();
private Singleton() {
System.out.println("인스턴스 생성했습니다.");
}
//인스턴스를 얻을 때 호출되는 메소드
static Singleton getInstance() {
//return new Singleton();
return s;
}
}
<Main.java>
package ch05.Sample;
public class Main {
public static void main(String[] args) {
Singleton obj1 = Singleton.getInstance();
Singleton obj2 = Singleton.getInstance();
if(obj1 == obj2) {
System.out.println("obj1과 obj2는 같은 인스턴스입니다.");
} else {
System.out.println("obj1과 obj2는 다른 인스턴스입니다.");
}
}
}
2. 연습 문제(1) - TicketMaker 클래스에 Singleton 패턴 적용하기
<TicketMaker.java>
package ch05.A1;
public class TicketMaker {
private int ticket = 1000;
private static TicketMaker singleton = new TicketMaker();
private TicketMaker() {
}
public static TicketMaker getInstance() {
return singleton;
}
// 한 스레드가 이 메소드를 호출해서 실행하는 동안
// 다른 스레드가 이 메소드를 호출하는 경우,
// 두 스레드가 모두 같은 값을 반환받는 경우가 발생할 수 있다.
// 왜?
// 다음과 같은 경우가 발생할 수 있다.
// ticket의 현재 값이 10이라고 하자.
// 스레드 A가 이 메소드를 호출 시 실행 시 ticket 값을 꺼내와서 1 올리기직전,
// CPU가 다른 스레드(B)에게 할당되어 이 메소드가 실행된다고 하자.
// 스레드 B로부터 호출된 메소드 실행이 먼저 끝난다면,
// 스레드 B는 11을 반환값으로 가져간다.
// 그 후 스레드 A가 나머지 부분을 실행하면 똑같이 11을 반환값으로 가져간다.
public synchronized int getNextTicketNumber() {
return ticket++; // 3가지 job으로 구성됨: ticket 값을 꺼내오고, 1 더하고, 다시 ticket 에 쓴다.
}
}
<Main.java>
package ch05.A1;
public class Main {
public static void main(String[] args) {
System.out.println("Start.");
for (int i = 0; i < 10; i++) {
System.out.println(i + ":" + TicketMaker.getInstance().getNextTicketNumber());
}
System.out.println("End.");
}
}
3. 연습 문제(2) - 인스턴스의 개수가 3개로 한정되어 있는 클래스 Triple 만들기
<Triple.java>
package ch05.A2;
public class Triple {
private static Triple[] triple = new Triple[]{
new Triple(0),
new Triple(1),
new Triple(2),
};
private int id;
private Triple(int id) {
System.out.println("The instance " + id + " is created.");
this.id = id;
}
public static Triple getInstance(int id) {
return triple[id];
}
public String toString() {
return "[Triple id=" + id + "]";
}
}
<Main.java>
package ch05.A2;
public class Main {
public static void main(String[] args) {
System.out.println("Start.");
for (int i = 0; i < 9; i++) {
Triple triple = Triple.getInstance(i % 3); //0,1,2
System.out.println(i + ":" + triple);
}
System.out.println("End.");
}
}
3. 연습 문제(3-1)
<Singleton.java>
package ch05.A3_1;
public class Singleton {
private static Singleton singleton = null;
private Singleton() {
System.out.println("인스턴스를 생성했습니다.");
slowdown(); // 생성 시 1초간 쉰다.
}
synchronized public static Singleton getInstance() {
//public static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
private void slowdown() {
try {
Thread.sleep(1000); // 이 메소드를 호출한 스레드는 1000 밀리초, 즉 1초가 CPU를 내놓고 쉰다.
} catch (InterruptedException e) {
}
}
}
<Main.java>
package ch05.A3_1;
// Thread 클래스를 상속받아서, Main 클래스 자신이 스레드가 된다.
public class Main extends Thread {
public static void main(String[] args) {
System.out.println("Start.");
// 스레드 3개를 생성한 후 실행시킨다.
new Main("A").start(); // run( ) 이 자동으로 실행된다.
new Main("B").start();
new Main("C").start();
System.out.println("End.");
}
public void run() {
Singleton obj = Singleton.getInstance();
System.out.println(getName() + ": obj = " + obj);//객체의 주소가 출력됨
}
public Main(String name) {
super(name);
}
}
4. 연습 문제(3-2)
<Singleton.java>
package ch05.A3_2;
public class Singleton {
private static Singleton singleton = null;
private Singleton() {
System.out.println("인스턴스를 생성했습니다.");
slowdown(); // 생성 시 1초간 쉰다.
}
public static Singleton getInstance() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
private void slowdown() {
try {
Thread.sleep(20000); // 이 메소드를 호출한 스레드는 1000 밀리초, 즉 1초가 CPU를 내놓고
// 쉰다.
} catch (InterruptedException e) {
}
}
}
<Main.java>
package ch05.A3_2;
public class Main {
public static void main(String[] args) {
System.out.println("Start.");
Singleton obj1 = Singleton.getInstance(); // 이 메소드 실행이 다 끝난 후에야
Singleton obj2 = Singleton.getInstance(); // 이 메소드가 실행된다.
if (obj1 == obj2) {
System.out.println("obj1과 obj2는 같은 인스턴스입니다.");
} else {
System.out.println("obj1과obj2는 같은 인스턴스가 아닙니다.");
}
System.out.println("End.");
}
}