Header

  1. View current page

    bjshim

Profile_image?t=1257826906&type=small
샤프-심
2

Collections.synchronizedCollection 메소드

Java Collection Framework의 대부분의 Collection 구현체들은 Thread-Safe하지 않으므로 멀티 스레드 환경이라면 반드시 synchronized block을 적절하게 잡아 주어야 합니다.

그런데, java.util.Collections 클래스의 static 팩토리 메소드인 Collections.synchronizedCollection 메소드를 이용하면 간편하게 Thread-Safe한 Collection 객체를 생성할 수 있습니다.

 

아래의 코드는 10000개의 스레드에서 1개의 TreeSet에 동시 접근해 Integer 객체의 삽입/삭제를 수행하는 코드로, 심각한 문제를 일으키는 코드입니다.

 

  1. import java.util.Collection;
    import java.util.TreeSet;
  2. public class SynchronizedCollectionEx {
  3.   //TreeSet은 Thread-Safe하지 않습니다.
      static Collection treeSet = new TreeSet();
      public static void main(String[] args){
          Thread[] t = new Thread[10000];
          for (int i = 0; i < 10000; i++){
              t[i] = new Thread(new WriterThread());
              t[i].start();
          }
      }
    }
  4. class WriterThread implements Runnable {
      public void run() {
          for (int i = 0; i < 100; i++){
              SynchronizedCollectionEx.treeSet.add(new Integer((int)(Math.random() * 10)));
              SynchronizedCollectionEx.treeSet.remove(new Integer((int)(Math.random() * 10)));
          }
      }
    }

 

 위 코드를 컴파일 - 실행하면 다음과 같은 예외가 줄기차게 발생하고, 급기야 deadlock에 빠지기도 합니다. 단일 프로세서 환경에서 실행했을 때는 그렇게 자주 발생하지는 않더군요. 하지만 듀얼 코어에서 돌리니 거의 항상 발생했습니다. 이런 오류는 잘 드러나 주는게 당근 도움입니다.

 

Exception in thread "Thread-119" java.lang.NullPointerException
        at java.util.TreeMap.fixAfterInsertion(TreeMap.java:2074)
        at java.util.TreeMap.put(TreeMap.java:559)
        at java.util.TreeSet.add(TreeSet.java:238)
        at WriterThread.run(Test.java:34)
        at java.lang.Thread.run(Thread.java:619)
Exception in thread "Thread-732" java.lang.NullPointerException
        at java.util.TreeMap.fixAfterInsertion(TreeMap.java:2074)
        at java.util.TreeMap.put(TreeMap.java:559)
        at java.util.TreeSet.add(TreeSet.java:238)
        at WriterThread.run(Test.java:34)
        at java.lang.Thread.run(Thread.java:619)
...

 

코드에서 공유 객체를 쓰거나 읽는 부분에 synchronized 블럭을 잘 잡아주어야 해결되는 문제입니다. 그리고, 또 하나의 간편한 해결책이 공유 객체인 treeSet 객체를 Thread-Safe한 객체로 재탄생 시키는 방법입니다. 이때 이용하는 static 메소드가

Collections.synchronizedCollection(Collection c)

입니다. 이 메소드는 인자로 들어온 Collection 객체를 래핑하여 Thread-Safe한 collection 객체를 반환합니다.

  1. import java.util.Collection;
  2. import java.util.Collections;
    import java.util.TreeSet;
  3. public class SynchronizedCollectionEx {
  4.  //treeSet은 Thread-Safe 하지 않습니다.
     static Collection treeSet = new TreeSet();
  5.  //synchronizedSet은 Thread-Safe 합니다. 이 객체를 공유 객체로 사용해야 합니다.
  6.  static Collection synchronizedSet = Collections.synchronizedCollection(treeSet);
     public static void main(String[] args){
         Thread[] t = new Thread[10000];
         for (int i = 0; i < 10000; i++){
             t[i] = new Thread(new WriterThread());
             t[i].start();
         }
     }
    }
  7. class WriterThread implements Runnable {
      public void run() {
        for (int i = 0; i < 100; i++){
          SynchronizedCollectionEx.synchronizedSet.add(new Integer((int)(Math.random() * 10)));
          SynchronizedCollectionEx.synchronizedSet.remove(new Integer((int)(Math.random() * 10)));
        }
      }
    }

 

java.util.Collections 클래스에는 synchronizedCollections 뿐만 아니라, SynchronizedSet, SynchronizedMap 등등 많은 Synchronized... 류의 static 팩토리 메소드를 제공합니다. 쓰는 방법은 크게 다르지 않습니다.

History

Last edited on 10/15/2008 01:47 by 심보준

Comments (0)

You must log in to leave a comment. Please sign in.