pungjoo

작성중 - Singleton에 대한 이해. 본문

JAVA

작성중 - Singleton에 대한 이해.

pungjoo.kim 2009.12.22 18:18
0. 들어가면서

일반적으로 singleton에 대해 설명하는 글을 보면 JVM상에 유일하게 인스턴화된 객체라고 표현합니다.
그러나 이는 엄밀히 말하면 JVM상에 classloader에 따른 유일하게 인스턴화된 객체가 맞는 표현입니다.

주의 : 싱글 인스턴를 만드는 방법을 설명하는 글이 아닙니다.


1. 경험

tomcat기준으로 1개의 process(jvm)에는 기본적으로 1개의 context를 정의해 사용하나 여러개의 context를 등록해 uri path로 구분해 서비스할 수 있습니다. 이런 경우에 과연 각각 context마다 WEB-INF/classes에 놓여 있는 singleton class가 jvm하에서 유일할까요? 어쩌구 저쩌구


2. 프로젝트 만들기 ( 편의상 이클립스 사용 )

다음과 같이 2개의 Java Project를 생성합니다.
 

( 이미지는 Romm이네 이런....  프로젝트 이름이 뭐 중요한가 그냥 ...)


3. 추상클래스 및 구현체 작성

00-commonRoom 프로젝트에서....

package info.yeonwoo.edu;

public abstract class Singleton {
      abstract public void printSum();
}

package info.yeonwoo.edu;

import info.yeonwoo.edu.Singleton;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

final public class SingletonImpl extends Singleton {

     final static private SingletonImpl INSTANCE = new SingletonImpl();

     final AtomicInteger counter = new AtomicInteger();

     private SingletonImpl() {
     }

     @Override
     public void printSum() {

          Thread t = new Thread() {

               public void run() {

                    AtomicLong sum = new AtomicLong();

                    for (int loop = 0; loop < 10; loop++) {
     
                         try {
                              Thread.sleep(10);
                         } catch (InterruptedException e) {
                         }

                         sum.addAndGet(counter.incrementAndGet());

                    }

                    System.out.println(Thread.currentThread() + " : Sum = " + sum.get());

               }
          };

          t.start();

     }

     public static Singleton getInstance() {
          return INSTANCE;
     }

}
 

4. 테스트

package info.yeonwoo.edu;

import info.yeonwoo.edu.Singleton;

public class SingletonTest1 {

     public static void main(String[] args) {

          for (int mainLoop = 0; mainLoop < 5; mainLoop++) {

               Singleton obj = SingletonImpl.getInstance();
               obj.printSum();

          }

     }

}

결과
Thread[Thread-0,5,main] : Sum = 235
Thread[Thread-1,5,main] : Sum = 245
Thread[Thread-2,5,main] : Sum = 255
Thread[Thread-4,5,main] : Sum = 265
Thread[Thread-3,5,main] : Sum = 275

위 소스에서 붉은 색 부분을 다른 형태로
package info.yeonwoo.edu;

import java.lang.reflect.Method;
import java.net.URLClassLoader;

public class SingletonTest2 {

     public static void main(String[] args) throws Exception {

          for (int mainLoop = 0; mainLoop < 5; mainLoop++) {

               URLClassLoader uc = (URLClassLoader) ClassLoader.getSystemClassLoader();

               Class clazz = uc.loadClass("info.yeonwoo.edu.SingletonImpl");
               Method method = clazz.getMethod("getInstance", new Class[] {});


               Singleton obj = (Singleton) method.invoke(new Object[] {}, new Object[] {});
               obj.printSum();

          }

     }

}

결과
Thread[Thread-1,5,main] : Sum = 248
Thread[Thread-4,5,main] : Sum = 272
Thread[Thread-2,5,main] : Sum = 249
Thread[Thread-0,5,main] : Sum = 240
Thread[Thread-3,5,main] : Sum = 266


5. 구현 클래스 및 테스트 클래스를 SingletonRoom 프로젝트로 이동

(1)과 같이 00-commonRoom 프로젝트에서 SingletonRoom으로 클래스 파일을 옮기면 ( 이미지는 Romm이네 이런.... )
(2)와 같이 오류가 발생하는데 이는 SingletonRoom 프로젝트에는 info.yeonwoo.edu.Singleton.class가 없기때문입니다.

SingletonRoom의 properties-> Java Build Path -> Projects -> Add -> 00-commonRoom 추가.


SingletonRoom 프로젝트로 옮긴 후 SingletonTest1 / SingletonTest2 를 각각 실행해 보세요. 결과는 동일함.

6. 이제 하고 싶은 말을 해 보자...

다시 00-commonRoom에 다음과 같은 Test 클래스를 만들어 보면... 위 Test2를 조금 변형 시켜서...
package info.yeonwoo.edu;

import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

public class SingletonTest3 {

     public static void main(String[] args) throws Exception {

          File file = new File("../SingletonRoom/bin/");

          for (int mainLoop = 0; mainLoop < 5; mainLoop++) {

               URLClassLoader uc = new URLClassLoader(new URL[] { file.toURI().toURL() }); 

               Class clazz = uc.loadClass("info.yeonwoo.edu.SingletonImpl");
               Method method = clazz.getMethod("getInstance", new Class[] {});

               Singleton obj = (Singleton) method.invoke(new Object[] {}, new Object[] {});
               obj.printSum();

          }

     }

}

결과
Thread[Thread-0,5,main] : Sum = 55
Thread[Thread-2,5,main] : Sum = 55
Thread[Thread-1,5,main] : Sum = 55
Thread[Thread-3,5,main] : Sum = 55
Thread[Thread-4,5,main] : Sum = 55

그럼 이런건 어떨까?
SingletonRoom 프로젝트에서

package info.yeonwoo.edu;

public class SingletonTest4 {

     public static void main(String[] args) throws Exception {

          SingletonTest3.main(null);

     }

}

결과
Thread[Thread-1,5,main] : Sum = 235
Thread[Thread-2,5,main] : Sum = 245
Thread[Thread-3,5,main] : Sum = 258
Thread[Thread-4,5,main] : Sum = 262
Thread[Thread-0,5,main] : Sum = 275

어쩌구 저쩌구~~~~~

이쯤에서 디렉토리 구조를 살펴 보면..


7. 결론...

어쩌구 저쩌구가 이래서 저래서 그렇다..


8. 소스

해당 소스를 이클립스에서 import하세요. ( general -> Existing Projeccts into Workspace -> Select archive file )

@
2 Comments
댓글쓰기 폼