2013-07-04 4 views
0

아래의 클래스를 살펴보고 아래 코드가 스레드로부터 안전한지 말해보십시오. 요점은 내 static 메서드와 그 메서드가 singleton 인스턴스의 메서드를 호출하는 한 클래스입니다. 또한 Runnable 인스턴스가 static 메서드를 호출합니다. 그래서 코드를 보도록 요청하고 있습니다 - static 메소드이고 멀티 스레드 환경에서 싱글 톤의 메소드를 호출합니다 - 안전합니까?싱글 톤 및 멀티 스레드

내 질문에 답변 해 주시면 정말 감사하겠습니다. 본질적으로

Thread 1    Thread 2 
--------    -------- 
test instance != null 
         test instance != null 
         finds it is 
finds it is 
creates, assigns 
         creates, assigns 
         returns 
returns 

, 이것은 더 이상 싱글되지 않습니다 :이 시나리오가 발생할 수 있기 때문에

import java.io.BufferedReader; 
import java.io.FileReader; 
import java.util.ArrayList; 
import java.util.HashMap; 
import java.util.List; 
import java.util.Map; 
import java.util.StringTokenizer; 

public class SingletonCls { 
    private static SingletonCls singletonInstance = null; 

    private SingletonCls() { 
    } 

    public static SingletonCls getIntance() { 
     if (SingletonCls.singletonInstance == null) { 
      singletonInstance = new SingletonCls(); 
     } 
     return SingletonCls.singletonInstance; 
    } 

    public List<Map<String, String>> call(String id) throws Exception { 
     List<Map<String, String>> list = new ArrayList<Map<String, String>>(); 
     BufferedReader br = null; 
     final String col = "col"; 
     try { 
      br = new BufferedReader(new FileReader("test.txt")); 
      String lineStr = null; 
      while ((lineStr = br.readLine()) != null) { 
       StringTokenizer st = new StringTokenizer(lineStr, ","); 
       int colIdx = 1; 

       if (lineStr.startsWith(id)) { 
        Map<String, String> map = new HashMap<String, String>(); 
        while (st.hasMoreTokens()) { 
         String value = st.nextToken(); 
         map.put(col + (colIdx++), value); 
        } 
        list.add(map); 
       } 
      } 

     } finally { 
      if (br != null) { 
       br.close(); 
      } 
     } 
     return list; 
    } 
} 


import java.io.IOException; 
import java.util.List; 
import java.util.Map; 

public class TestSingleTonCaller { 

    public static List<Map<String, String>> getData(String id) throws Exception { 
     List<Map<String, String>> list = SingletonCls.getIntance().call(id); 
     return list; 
    } 
} 



import java.io.IOException; 
import java.util.List; 
import java.util.Map; 

public class RunnableSingleTonExe implements Runnable { 
    private final String id; 

    public RunnableSingleTonExe(String inId) { 
     this.id = inId; 
    } 

    public void run() { 
     try { 
      List<Map<String, String>> list = TestSingleTonCaller 
        .getData(this.id); 
      System.out.println("thread id:" + this.id + " list > " 
        + (list == null ? "" : list.toString())); 
     } catch (IOException e) { 
      Thread.currentThread().interrupt(); 
      e.printStackTrace(); 
     } catch (Exception e) { 
      e.printStackTrace(); 
     } 
    } 
} 
+3

올바르게 싱글 톤을 만들지 않으므로 아니오입니다. 'SingletonCls'인스턴스가 하나만 있다고 보장 할 수는 없습니다. 싱글 톤을 위해서 자바에서'enum'을 사용하십시오. –

+2

'SingletonCls # getInstance' 메쏘드는 쓰레드에 안전하지 않습니다. 'singletonInstance'를 게으른 로딩 대신 처음부터 초기화하는 것이 더 낫습니다. –

+0

@Yoonyou Ryu - Brain과 Luiggi가 지적했듯이, 이것은 스레드 안전하지 않으며 더 나은 접근법이 있습니다. 이를 수행하는 다른 방법은 http://stackoverflow.com/questions/3635396/pattern-for-lazy-thread-safe-singleton-instantiation-in-java를 참조하십시오. – lreeder

답변

1

그것은 안전하지 않습니다.

또한 singletonInstance은 변동이 없으므로 스레드 중 어느 인스턴스가 반환되는지를 보장 할 수 없습니다.

쉬운 수정, 생성자는 아무것도하지 않습니다 이후 :

private static final SingletonCLS INSTANCE = new SingletonCLS(); 

public static SingletonCLS getInstance() { return INSTANCE; } 

다른 가능한 솔루션 :

  • 이 열거를 사용합니다;
  • 은 지연 초기화 홀더 클래스를 사용합니다.
+0

답변 해 주셔서 감사합니다. :) 나는 또한 그의 동료에게 그러한 시나리오에 관해 이야기했지만 그는 듣지 않았다. 하지만 코드가 잘못되었다는 것을 확신 할 수 있습니다. 나는 다시 그에게 말할거야. 다시 한번 감사드립니다. –

0

우선 내가 여기에 싱글 톤이 필요하다고 생각하지 않습니다. 싱글 톤 클래스에는 인스턴스 변수가 없습니다. 방법은 아주 잘 정적 일 수 있었다. 따라서 Singleton이 필요하지 않은 상황에서 Thread Safe를 사용합니다.

둘째, 싱글 톤이 잘못되었습니다 (필요한 경우). Effective Java Item 71 (지연 초기화 홀더 클래스 관용구)을 사용해보십시오.

두 번째 동일한 파일을 반복해서 열지 않는 것이 좋습니다. 메모리의 데이터를 더 잘 읽고 캐시 한 다음 ID를 찾으십시오. 이 경우 SingleTon 객체가 필요합니다.

+0

답변 해 주셔서 감사합니다. N 또한 게으른 초기화가 필요 없다고 생각합니다. 나는 동료에게 그것을 고쳐 줄거야. –

0

getIntance() 메서드는 스레드로부터 안전하지 않습니다. 그리고 위의 답에 지정된대로 SingletonCls의 개체가 하나 이상 생성 될 수 있습니다.

public class SingletonCls 
{ 
    public static SingletonCls getInstance() 
    { 
     return LazyClass.getInstance(); 
    } 
    private static class LazyClass 
    { 
     public static SingletonCls instance = new SingletonCls(); 
     public static SingletonCls getInstance() 
     { 
      return instance; 
     } 
    } 
} 

이들이 참조 될 때까지 내부 클래스가로드되지 않는다는 사실에 의존 : 는 다음 코드를 사용한다 게으른 인스턴스와 클래스의 싱글 버전을 얻으려면. 이 싱글 톤 클래스를 만드는 방법은 다음과 같습니다. Initialization on Demand Holder

+0

lazy initialization holder의 링크를 가져 주셔서 감사합니다. 나는 게으른 초기화를 사용하기를 원한다면 동료에게 링크를 알리고 싱글 톤 홀더를 사용할 것입니다. 다시 한번 감사드립니다. –