2011-02-11 4 views
0

좋아, 여기 내 문제가있다.자바 싱글 톤 스레드 안전

내 클라이언트 응용 프로그램에서 여러 연결을 처리 할 수있는 소켓 프로그램을 만들어야합니다 (apps1이라고 할 수 있음). 이 스레드를 사용하여 처리합니다 (그래서 각 연결 새 스레드로 던졌습니다)

문제는 내가 열려있는 모든 연결에서 요청을 수락하지만 응답을 보낼 때 나는 최신 연결을 통해서만 보내야합니다. 그래서 만약 내가 con1, con2와 con3에서 3 개의 연결 (con1, con2, con3) 요청을 받아 들일 수 con3 통해 응답을 보내야합니다 (con3가 최신 연결 가정)

나는 싱글 톤을 사용하여 생각, PrintWriter 매개 변수로. 그래서 새로운 연결이있을 때마다 그들은 싱글 톤을 호출하고 매개 변수를 업데이트하고 응답을 보내려고 할 때 보내기 전에 먼저 PrintWriter를 얻습니다. 여기

내 싱글 톤 클래스입니다 :

public class Singleton { 

private static final Singleton instance = new Singleton(); 

PrintWriter out; 

public static Singleton getInstance() { 
    return instance; 
} 
public Singleton() 
{ 
    if (instance != null) { 
     throw new IllegalStateException("Already instantiated"); 
    } 
} 

public PrintWriter getPrintWriter() 
{ 
    return this.out; 
} 
public void updatePrintWriter (PrintWriter out){ 
    this.out = out; 
} 
} 

이 내 주요 프로그램 :

public class SocketAccept{ 
private ServerSocket mainSocket; 
private Socket clientSocket; 

    public SocketAccept (int portNumber) { 
     Singleton s = Singleton.getInstance(); 
     do { 
     try { 
      mainSocket = new ServerSocket(portNumber); 
      clientSocket = mainSocket.accept(); 
      s.updatePrintWriter(new PrintWriter(clientSocket.getOutputStream(), true)); 
      ClientThread (clientSocket); 
     } catch (IOException ex) { 
      Logger.getLogger(TestClass.class.getName()).log(Level.SEVERE, null, ex); 
     } 
     }while (true);//need to change this into thread pool or connection pool  
    } 
} 

이것은 처리 내 스레드 소켓 :

public class ClientThread extends Thread { 

    private Socket cs; 
    Singleton s = Singleton.getInstance(); 
    PrintWriter out; 

    private String read(Socket sc) { 
     String request = ""; 
     //read request here 
     return request; 
    } 

    private String process(String request) { 
     String response = ""; 
     //process request here 
     return response; 
    } 

    public ClientThread(Socket clientSocket) { 
     this.cs = clientSocket; 
    } 

    @Override 
    public void run() { 
     String requestMsg = ""; 
     String responseMsg = ""; 
     do { 
      requestMsg = read(cs);// read the message 

      if (requestMsg.equalsIgnoreCase("SHUTDOWN")) { 
       break; 
      } 
      responseMsg = process(requestMsg); 
      out = s.getPrintWriter(); 
      out.write(responseMsg); 
     } while (true); 
    } 
} 

내가 해냈어 수행 권리? 아니면 싱글 톤으로하는 것은 불가능합니까?

도움 주셔서 감사합니다.

+0

열려있는 모든 연결이 항상 최신 스트림으로 인쇄되어야하는 이유를 설명해 주실 수 있습니까? –

+0

포스터가 요구 사항을 설명하기를 원하십니까? 그게 바보 같지 않니? 마치 기술적으로 실행 불가능한 질문을하는 것만은 아닙니다. –

+0

@ 스크럼 마이스터 (Scrum Meister) 만약 내가 할 수 있다면 보통 (이유를 알면 다른 해결책이 있기 때문에) 이유를 설명 할 것이고, 슬프게도 클라이언트는 아무런 설명없이 질문 할 것입니다. – Willy

답변

3

불행히도, 이것은 싱글 톤 패턴의 스레드 안전 구현이 아닙니다. 나는이 경우에 하나가 필요하다고 생각하지 않는다. AtomicReference은 아마 잘 동작 할 것이다. 이 시도 :

public class SocketAccept{ 
    private ServerSocket mainSocket; 
    private Socket clientSocket; 

    private final AtomicReference<PrintWriter> printWriterHolder = new AtomicReference(null); 

    public SocketAccept (int portNumber) { 
     Singleton s = Singleton.getInstance(); 
     do { 
     try { 
      mainSocket = new ServerSocket(portNumber); 
      clientSocket = mainSocket.accept(); 
      printWriterHolder.set(new PrintWriter(clientSocket.getOutputStream(), true)); 
      Thread clientThread = new ClientThread (clientSocket, printWriterHolder); 
      clientThread.start(); 
     } catch (IOException ex) { 
      Logger.getLogger(TestClass.class.getName()).log(Level.SEVERE, null, ex); 
     } 
     }while (true);//need to change this into thread pool or connection pool  
    } 
} 

...

public class ClientThread extends Thread 
    ... 
    private final AtomicReference<PrintWriter> printWriterHolder; 
    public ClientThread(Socket clientSocket, AtomicReference<PrintWriter> holder) { 
     this.cs = clientSocket; 
     this.printWriterHolder = holder; 
    } 

    @Override 
    public void run() { 
     String requestMsg = ""; 
     String responseMsg = ""; 
     do { 
      requestMsg = read(cs);// read the message 

      if (requestMsg.equalsIgnoreCase("SHUTDOWN")) { 
       break; 
      } 
      responseMsg = process(requestMsg); 
      out = printWriterHolder.get(); 
      out.write(responseMsg); 
     } while (true); 
    } 
} 

당신이 정말로 싱글 톤 패턴을 사용하고자하는 경우는, 여기에 문제가를 만들기위한 좋은 스레드 안전 구현이 SO에서 참조입니다 싱글 톤 : Java Singleton Pattern

또한 necessa로 (.. AtomicInteger, AtomicReference 등) synchronized, Lock, 또는 원자 연산을 사용하여 싱글의 상태 스레드 안전에 접근 할 필요가있을 것이다 너.

+0

와우, 나는 " AtomicReference를 사용하는 "간단한"솔루션입니다 (이 기사를 읽은 것은 이번이 처음입니다). 대단히 감사합니다. – Willy