Chapter 5. Singleton : 단 하나의 인스턴스

sua·2022년 4월 9일
0
post-thumbnail

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.");
	}
}

profile
가보자고

0개의 댓글

관련 채용 정보