2009-04-03 2 views
8

그래서 두 개의 스레드가 있습니다.Java 소켓의 PrintWriter 스레드가 안전합니까?

스레드 1은 클라이언트 연결을 관리합니다. (단 하나의 클라이언트와 하나의 서버가 있습니다.)
나는 이것을 내 서버 스레드라고 부릅니다.

스레드 2는 클라이언트에 메시지를 보내는 것을 관리합니다. 나는 그것을 내 메시지 프로세서 스레드라고 부른다.

스레드 하나는 클라이언트에 주기적으로 하트 비트를 보내는 역할을 담당합니다.

프로그래밍 할 때 소켓이 스레드 안전하지 않았지만 버퍼가 있고 서버와 프로세서 스레드에 별도의 버퍼를 사용하는 한 정상이라고 가정했습니다.

또한 "PrintWriter"가 Java의 소켓 버퍼와 비슷하다고 가정했습니다. 이러한 가정 하에서

나는 하트 비트 전송이 기능을 썼다

public void sendHeartBeat(){ 
     logger.info("Sending a hearbeat!"); 
     PrintWriter printWriter=null; 
     try { 
      printWriter = new PrintWriter(clientSocket.getOutputStream()); 
     } catch (IOException e) { 
      logger.info(e.toString()); 
     } 
     if(printWriter!=null){ 
      printWriter.print("HEARTBEAT#"); 
      printWriter.flush(); 
     } 
    } 

다른 스레드의 "프로세서"한 그 비슷한 무언가를 그것을 수행합니다

printWriter=new PrintWriter(theServer.getClientSocket().getOutputStream()); 

을 이러한 방식으로 하트 비트를 보내려고 할 때마다 새로운 "버퍼"를 만들 것이고, 내 메시지는 결코 덮어 쓰지 않을 것입니다.

불행하게도이 경우가 아닌 것 같습니다. 그리고 다음과 같이 파이프를 통해 오는 메시지가 나타납니다. dsgdsbHEARTBEAT # sdg

이렇게하면 나중에 코어 덤프가 발생합니다.

1 소켓 분명히 스레드 안전하지 않음),하지만 난 그들로부터 얻을 PrintWriters 스레드 안전 :

여기 내 질문은? 아니면 그냥 동일한 PrintWriter를 반환입니까?

2) Java의 소켓 버퍼와 비슷한 점은 무엇입니까? 이 문제에 대해 어떻게 생각해야합니까?

3)이 스레드가 소켓의 동일한 버퍼에 쓰지 않도록하려면 어떻게해야합니까?

답변

10

같은 스트림에 여러 개의 PrintWriter 개가있는 것은 좋지 않습니다. 실제로 적어도 동기화 된 (또는 스레드 제한된) 개체를 원합니다.

그러나, 여러 PrintWriter들 싶어 몇 가지 이유로 가정 :

첫 번째 문제 : Writer의 잠금으로 this을 사용하지 마십시오. PrintWriterBufferedWriter은 기본적으로 모두 자물쇠로 구성된 Writer을 사용합니다. 이것은 분명히 완전히 깨졌습니다. 그들은 Writer 그 자체가 아니라 Writer의 자물쇠를 사용해야합니다.Object 기능을 잠그면 정적 유형 안전이 제거된다는 것을 쉽게 알 수 있습니다. 소켓 OutputStream (또는 다른 공통 객체)을 자물쇠로 사용하여 PrintWriter을 생성해야합니다.

둘째, 버퍼링은 PrintWriter입니다. 그래서 버퍼의 끝으로 와서, 반은 쓰고, 반은 다음 쓰기를 기다린다. 이를 방지하려면 printflush을 외부 적으로 잠 그거나 자동 줄 바꿈을 사용하고 줄 바꿈 문자를 추가하십시오.

따라서 은 의미가있어 스레드 안전하지만 해킹 할 수 있습니다. 또는 더 나은 디자인을 사용할 수 있습니다.

+0

자바 SE 1.6.0_31 src를 살펴 보았습니다. 'PrintWriter (Writer out)'는 궁극적으로 보호 된 Writer (Object Lock)를 호출하고 'Writer'는이 'Lock'을 'Writer'에서 동기화에 사용되는 내부 'Lock'에 할당합니다. 그럼 너도 그럴 수있어. 왜 여기에 잠금 장치가 고장 났다고 생각하는지 설명해주십시오. – shrini1000

+0

@ shrini1000'PrintWriter'는'Writer (Object lock)'를'super (out);'로 호출합니다. 그러므로'lock.lock' 대신'lock'이'out'입니다. (이것은 구현상의 문제입니다. 사양이 누락 된 것으로 보입니다.) –

+0

Java 8 - PrintWriter에서 super (out)을 호출하고 out.lock 대신 lock이있는 경우에도 여전히 나타납니다. –

4

동일한 PrintWriter을 스레드 (t1.writer == t2.writer, 동일하게 작성한 PrintWriters가 아닌 OutputStream)를 사용하는 방법이 필요합니다. PrintWriter과 동일하게 모든 쓰기 작업이 동기화됩니다.

+1

PrintWriters는 스레드로부터 안전하지만 OutputStreams는 그렇지 않다고 말하는 것입니까? – Alex

+3

저는 Chris가 PrintWriter는 쓰레드 안전하다고 말하지만 같은 스트림에있는 두 개는 의미있는 쓰레드 안전성을 보장하지 않습니다. 그러므로 하나를 사용하십시오. –

관련 문제