2011-12-03 3 views
2

Java로 다중 스레드 프로그램을 작성합니다. 새 클라이언트 연결을 처리 할 별도의 스레드를 만듭니다. 나는이 다음 ClientHandler에 스레드에서 Java에서 서버 프로그램을 사용하고 Socket 객체에 대한 참조를 전달합니다.

Socket s; 


while(true) 
{ 
    s = server.accept(); 
    ClientHandler ch = new ClientHandler(s); 
    Thread servingThread = new Thread(ch); 
    servingThread.start(); 
} 

내가이 : 자바에서 내가 객체하지만에만 참조를 전달 할 수없는 경우

,
public class ClientHandler implements Runnable 
{ 
    private Socket s; 

public ClientHandler(Socket _Socket, boolean _accepted, BaseStation _bs) 
{ 
    this.s = _Socket; 
} 

되지 않는다는 문제가 발생할 것 server이 새 연결을 허용 할 때마다 ClientHandler 내부의 s 인스턴스에 연결 하시겠습니까? ClientHandler 내부도 변경되지 않고 손상 될 수 있습니까? 그렇다면 올바른 방법은 무엇입니까?

답변

2

Socket 개체 (Java의 다른 개체와 마찬가지로)가 참조로 전달되므로 다른 모듈이나 다른 스레드에서 참조 될 가능성이 있으므로 예기치 않은 동작이 발생할 수 있습니다.

그러나 프로그램의 경우에는 문제가 없습니다. 그 이유는 서버가 새로운 연결을 수락 할 때마다 새로 Socket 개체가 생성되어 인스턴스 인 ClientHandler으로 전달되기 때문입니다. 따라서 클라이언트로부터의 모든 새로운 연결은 독립적 인 ClientHandler 인스턴스에 의해 제공 될 것이므로, Socket 개체가 걱정할 경쟁 조건은 없습니다. 이제 당신은 안전합니다. 카운터 - 예를 들어

는이 같은 같은 Socket 객체에서 읽기 두 ClientHandler 스레드를 만들 것을 결정하는 경우에 ...

s = server.accept(); 
ClientHandler ch = new ClientHandler(s); 
ClientHandler ch2 = new ClientHandler(s); 
new Thread(ch).start(); 
new Thread(ch2).start(); 

... 두 ClientHandler s는 같은Socket 객체에 같은 참조를 얻을 것이다 모두 시도가 같은 소켓에서 읽을 경우가 각각 절반을 얻을 것이기 때문에 당신은 문제가 될 수있다 데이터의 예 : 문자열이 "hello" 인 경우 ch으로 끝나고 "hel"ch2"lo"으로 표시되거나 다른 조합으로 표시 될 수 있습니다.

1

다소 혼란 스럽지만 코드는 표시된대로 작동해야합니다. Java는 값으로 처음 전달 된 다음 참조로 전달됩니다. I.E., "Socket s"에 대한 포인터는 전달하지 않지만 전달할 때의 실제 값은 "s"입니다.

단순화하고 혼동을 없애기 위해 앞으로 선언문 인 "Socket s;"을 제거하고 루프의 첫 번째 줄을 "Socket s = server.accept();"으로 지정합니다.

+1

normalocity - http://stackoverflow.com/questions/589919/does-java-pass-by-reference, http://www.javaworld.com/javaworld/javaqa/2000-05/03-qa-0526 -pass.html과 다른 것들은 자바가 우선적으로 가치를 인정한다는 것을 확인시켜 준다. – ziesemer

+0

정확히, Java는 먼저 값에 의해 전달 된 다음 참조로 전달됩니다. :-) – ziesemer

+0

우리는 값에 의해 해석되는 "컨테이너"를 전달하여 참조에 의한 통과를 강제 할 수 있으며, 값을 실제 참조로 유지합니다. I.E., Socket [] socketHolder = 새로운 소켓 [1]; socketHolder [0] = s입니다. 그렇다면 OP가 단순히 "s"대신에 socketHolder [0]을 사용한다면 소켓을 참조로 전달할 것이고 문제가 발생할 것입니다. – ziesemer

2

설명하려면 Is Java "pass-by-reference" or "pass-by-value"?을 참조하십시오. ClientHandler 내부의 Socket 인스턴스의 복사본에 영향을주지 않는 지역 변수 s의 값을 변경 - 각 ClientHandler 자체 Socket을 가지고 있기 때문에 새로운 ClientHandler 인스턴스에 새로운 Socket 인스턴스를 전달

괜찮습니다.

이이 문제가 발생할 것 처럼 뭔가 :

ClientHandler ch = new ClientHandler(s); 
Thread servingThread = new Thread(ch); 
servingThread.start(); 

s.someMethod(); // close, read etc. 

ch.ss 동일한 기본 Socket 개체 인스턴스에 두 점 때문입니다.

BTW : 완전히 새로운 스레드를 while 루프에서 회전시키는 것은 해당 스레드가 종료되지 않는 한 나쁜 것입니다. 아마 ThreadPool을 사용하는 것이 좋습니다.

관련 문제