> Java > java지도 시간 > Java를 처음 배우는 초보자를 위한 메모 (9)

Java를 처음 배우는 초보자를 위한 메모 (9)

黄舟
풀어 주다: 2016-12-20 13:55:23
원래의
1062명이 탐색했습니다.


인터페이스를 사용하여 멀티스레딩을 구현하는 것과 클래스를 사용하여 스레드 본문을 구성하는 것의 차이점을 갑자기 발견했습니다. 이전에는 클래스를 사용하여 스레드 본문을 구성할 때 이에 대해 별로 주의를 기울이지 않았던 것 같습니다. 이 클래스를 사용하여 스레드를 정의하려면 MyThread thread1=New MyThread()와 같은 객체를 사용하고 인터페이스를 사용하여 스레드 본문을 생성할 때는 Thread thread1=new Thread(MyThread)와 같은 Thread 클래스만 사용해야 합니다. 며칠 전에 언급한 멀티스레딩이 소켓에 반영되었습니다.

그동안의 끊임없는 노력으로 인해 미완성이었던 원래 작업을 계속할 수 있었고 공식적으로 소켓 연결 풀 버전으로 나아갈 수 있었습니다.

만든 방법을 검토합니다. 멀티 스레드 서버 MultiThreadRemoteFileServer의 경우 지난 며칠 동안의 내용을 요약하면 연결을 기다리는 각 클라이언트마다 새 스레드를 사용한다는 것입니다. 클라이언트가 연결을 신청할 때마다 새 스레드에 새 ConnectionHandler를 생성합니다(참고: 인터페이스에 의해 생성된 스레드 본문 사용). 이는 분명히 전체 시스템에서 12개의 스레드가 실행될 수 있음을 의미합니다. 연결된 클라이언트 수가 증가함에 따라 시스템 오버헤드도 계속해서 증가할 것입니다. 따라서 오버헤드가 일정 수준까지 증가하면 시스템이 이를 감당할 수 없을 가능성도 고려해야 합니다. 따라서 이를 제한할 수 있는 방법을 찾아야 합니다. 연결된 클라이언트 수를 늘리고 서버 효율성을 향상시킵니다.

그러면 해결 방법은 다음과 같습니다. 서버 측에서는 서버가 시작될 때 특정 수의 PooledConnectionHandler를 생성합니다. 들어오는 연결을 연결 풀에 넣습니다. PooledConnectionHandler가 나머지를 처리하도록 합니다. 클라이언트 프로그램을 전혀 수정할 필요가 없습니다. 이 디자인의 장점은 다음과 같습니다.

1. 허용되는 동시 연결 수를 제한합니다.
2. 제한된 횟수만큼 PooledConnectionHandler 스레드를 시작하면 됩니다.

이 두 문장의 의미는 후속 프로그램에 반영됩니다.

java.io.* 가져오기;
java.net.* 가져오기;
java.util.* 가져오기;

public class PooledRemoteFileServer {
PRotected int maxConnections;// 동시에 처리할 수 있는 클라이언트 정의 최대 연결 수 protected int listeningPort;//
protected ServerSocket serverSocket;

을 수신할 포트 번호 정의 public PooledRemoteFileServer(int aListenPort, int maxConnections) {
listenPort = aListenPort;
this .maxConnections = maxConnections;
}
public static void main(String[] args) {
}
public void setUpHandlers(){//PooledConnectionHandler 생성 다수의 maxConnections
}
public void acceptConnections(){//ServerSocket에서 들어오는 클라이언트 연결을 수신합니다. 이는 이전 RemoteFileServer 및 MultiThreadRemoteFileServer
}protected void handlerConnection(Socket receivedConnection) {
}//Connection handler
}

마찬가지로 먼저 메인 함수를 살펴보세요
public static void main(String[] args) {
PooledRemoteFileServer server = new PooledRemoteFileServer(3000, 3) ;
server.setUpHandlers();//이전 서버의 기본 기능과 달리 먼저 연결 풀을 생성해야 하며 여기에는 3개의 사용 가능한 연결 핸들러가 있습니다
server.acceptConnections();//준비되면 듣기 시작

3개의 ConnectionHandler를 생성하는 프로그램을 구현하는 방법을 살펴보겠습니다.

public void setUpHandlers(){
for (int i = 0; i < maxConnections ; i++) {
PooledConnectionHandler currentHandler = new PooledConnectionHandler();
new Thread(currentHandler, "Handler " + i).start();
}
}

setUpHandlers() 메소드는 maxConnections PooledConnectionHandlers를 생성하고 이를 새 Thread에서 활성화합니다. 여기서는 인터페이스(Runnable)로 구현된 스레드 본문이 있습니다. Runnable을 구현하는 객체로 Thread를 생성하면 start()를 호출할 수 있습니다. ) 스레드에서 run()이 Runnable에서 호출될 것으로 예상합니다. 즉, PooledConnectionHandler는 각각 자체 스레드에서 들어오는 연결을 처리하기를 기다립니다. 이 예에서는 세 개의 스레드만 생성하며 서버가 실행되면 변경할 수 없습니다.

여기에서는 acceptConnections() 메서드가 생략됩니다. 연결 핸들러를 살펴보세요. );
}

여기서 연결 핸들러는 PooledConnectionHandler 스레드 클래스의 processRequest 클래스 메소드를 직접 호출하여 모니터링되는 연결을 처리합니다. 분명히 이 processRequest는 정적 메소드입니다.

PooledRemoteFileServer 클래스 모든 메서드에는 중요한 스레드 클래스인 PooledConnectionHandler가 포함됩니다. 인터페이스로 구현된 클래스가 어떤 모습인지 살펴보겠습니다.

공용 클래스 PooledConnectionHandler는 Runnable을 구현합니다. {
보호된 소켓 연결;// 현재 처리 중인 소켓
protected static List pool = new LinkedList();//정적 LinkedList 풀은 처리해야 하는 연결을 저장합니다. 즉, LinkedList를 사용하여 연결 풀을 시뮬레이션합니다
public PooledConnectionHandler() {//생성자
}
public void handlerConnection() {//연결에 대한 I/O 작업은 여기에 있습니다
}
public static void processRequest(Socket requestToHandle) {//고객 연결을 처리하고 이를 연결 풀에 추가
}
public void run() {//연결이 올 때까지 기다립니다. ) 처리용
}
}

이 클래스는 멀티스레드 소켓데이의 ConnectionHandler와 매우 유사하다는 것을 알 수 있지만 차이점은

먼저 리스너 프로그램
public static void processRequest(Socket requestToHandle) {
synchronized(pool){pool.add(pool.size(), requestToHandle) ;
pool.notifyAll();
}
}

여기서 requestToHandle은 처리할 클라이언트 연결 소켓입니다. processRequest가 수행하는 작업은 연결 풀에 클라이언트 연결을 추가하는 것이라고 할 수 있습니다. 그러나 연결 풀(Pool)을 작동할 때 다른 스레드의 간섭이 없는지 확인하려면 해당 개체의 잠금을 얻어야 합니다. 연결 풀 및 동기화 블록 사용 이전에 배운 동기화 개념을 여기서 사용할 수 있습니다.

이제 우리는 "웨이딩"하는 유일한 사람임을 확인했습니다. LinkedList의 끝에 들어오는 소켓을 추가하면 pool.notifyall을 사용하여 풀을 기다리는 다른 스레드에 알릴 수 있으며 이제부터 사용할 수 있습니다. 또 다른 관점에서는 일부 조건이 이미 충족되었음을 알리는 것이라고 할 수도 있습니다.

그럼 이 대기 스레드는 무엇인가요?

PooledConnectionHandler에 run() 메서드를 구현해 보겠습니다. 연결 풀에서 대기하고 풀에 연결이 있는 즉시 처리하므로 연결을 처리해야 하는 스레드가 대기 중입니다.

public void run() {
while (true) {
동기화됨(풀) {
while(pool.isEmpty( )) {
try {
pool.wait();
} catch(InterruptedException e) {return; }
}
connection = (Socket) pool.remove(0);/ /풀의 첫 번째 연결을 잡고 곧 처리될 연결로 만듭니다
}
handleConnection(); //그런 다음 처리를 위해 handlerConnection에 넘깁니다.
}
}

이 함수는 각 PooledConnectionHandler 스레드가 주로 실행되는 내용을 알려줍니다. 당연히 연결된 연결이 있는지 지속적으로 확인합니다. 커넥션 풀에 있으면 바로 처리되니까 '커넥션 풀'을 기다리고 있는 거죠. '연결됨'이라는 조건이 있는데, 이 조건이 충족됐다고 누가 알겠습니까? processRequest가 알림(pool.notify())을 보내면 이 조건이 충족되고 run() 연결의 핸들러는 더 이상 기다릴 필요가 없으며 즉시 처리를 위해 연결될 수 있습니다. 반면에 이 조건이 충족될 때까지 wait()가 위치한 스레드는 여전히 차단된 상태, 즉 정체 상태에 있을 것입니다. 왜냐하면 풀도 작동해야 하므로 여기에서도 동기화된 블록을 사용해야 합니다. 🎜>
객체 잠금의 개념을 다시 살펴보겠습니다. run()이 풀의 뮤텍스 잠금을 소유한 경우 processRequest()가 풀에 연결을 넣는 것은 어떻습니까? 대답은 풀에서 wait()를 호출하면 잠금이 해제되고, wait()는 자체적으로 반환되기 전에 다시 잠금을 잡는 것입니다. 이렇게 하면 풀 개체의 다른 동기화 코드가 잠금을 획득할 수 있습니다.

마지막으로 PooledConnectionHandler 스레드의 handlerConnection() 메서드를 살펴보겠습니다. 다중 스레드 서버와 달리 PooledConnectionHandler에는 handlerConnection() 메서드가 있습니다. 이 메서드의 코드는 풀링되지 않은 다중 스레드 서버에 있는 ConnectionHandler의 run() 메서드와 정확히 동일합니다. 먼저, OutputStream과 InputStream을 (소켓의 getOutputStream()과 getInputStream()을 사용하여) 각각 BufferedReader와 PrintWriter로 래핑합니다. 그런 다음 멀티스레드 예제에서 했던 것처럼 대상 파일을 한 줄씩 읽습니다. 다시 한 번, 우리는 일부 바이트를 가져와 로컬 라인 변수에 넣은 다음 클라이언트에 씁니다. 읽기 및 쓰기 작업을 완료한 후 FileReader와 열린 스트림을 닫습니다.

말하자면, 프로그램에는 PooledRemoteFileServer와 PooledConnectionHandler라는 두 가지 클래스가 있다는 것을 알 수 있습니다. PooledRemoteFileServer는 연결 요청을 직접 처리하지 않고 이러한 연결을 모니터링하고 연결 풀로 반환하는 역할만 담당합니다. 처리의 특정 측면은 모두 PooledConnectionHandler에 의해 처리됩니다.

Connection Pool을 갖춘 서버가 완성되었습니다. "풀링된" 서버를 만들고 사용하는 단계를 검토해 보겠습니다.

1. 풀링된 연결을 처리하기 위한 새로운 유형의 연결 처리기(PooledConnectionHandler라고 함)를 만듭니다.
2. PooledConnectionHandler 세트를 생성하고 사용하도록 서버를 수정합니다.

첨부: PooledRemoteFileServer.java 소스 코드

import java.io.*;
import java.net.*;
import java.util.*;

공용 클래스 PooledRemoteFileServer {
protected int maxConnections;
protected int listeningPort;
protected ServerSocket serverSocket;
public PooledRemoteFileServer(int aListenPort, int maxConnections) {
listenPort = aListenPort;
this.maxConnections = maxConnections;
}
public void acceptConnections() {
try {
ServerSocket 서버 = new ServerSocket(listenPort, 5);
소켓comingConnection = null;
while(true) {
incomingConnection = server.accept();
handleConnection(incomingConnection);
}
} catch(BindException e) {
시스템 .out.println("포트에 바인딩할 수 없습니다. " + listeningPort);
} catch(IOException e) {
System.out.println("포트에서 ServerSocket을 인스턴스화할 수 없습니다: " + listeningPort);
}
}
protected void handlerConnection(Socket ConnectionToHandle) {
PooledConnectionHandler.processRequest(connectionToHandle);
}
public static void main(String[] args) {
PooledRemoteFileServer server = new PooledRemoteFileServer(3000, 3);
server.setUpHandlers();
server.acceptConnections();
}
public void setUpHandlers() {
for (int i = 0 ; i < maxConnections; i++) {
PooledConnectionHandler currentHandler = new PooledConnectionHandler();
new Thread(currentHandler, "Handler " + i).start();
}
}
}

PooledConnectionHandler 클래스는 Runnable을 구현합니다. {
보호된 소켓 연결;
보호된 정적 목록 풀 = new LinkedList();
public PooledConnectionHandler() {
}
public void handlerConnection () {
시도 {
PrintWriter streamWriter = new PrintWriter(connection.getOutputStream());
BufferedReader streamReader = new BufferedReader(new InputStreamReader(connection.getInputStream()));

String fileToRead = streamReader.readLine();
BufferedReader fileReader = new BufferedReader(new FileReader(fileToRead));

String line = null;
while ((line = fileReader.readLine()) != null)
streamWriter.println(line);

fileReader.close();
streamWriter.close();
streamReader.close();
} catch( FileNotFoundException e) {
System.out.println("서버에서 요청한 파일을 찾을 수 없습니다.");
} catch(IOException e) {
System.out.println("클라이언트 처리 오류 : " + e);
}
}
public static void processRequest(Socket requestToHandle) {
synchronized (pool) {
pool.add(pool.size(), requestToHandle);
pool.notifyAll();
}
}
public void run() {
while(true) {
synchronized(풀) {
while(pool.isEmpty) ()) {
try {
pool.wait();
} catch (InterruptedException e) {
return;
}
}
connection = (소켓) 풀 .remove(0);
}
handleConnection();
}
}

 以上就是菜鸟初학Java의 备忘录(九)的内容,更多相关内容请关注PHP中文网(www.php.cn)! 


관련 라벨:
원천:php.cn
본 웹사이트의 성명
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.
인기 튜토리얼
더>
최신 다운로드
더>
웹 효과
웹사이트 소스 코드
웹사이트 자료
프론트엔드 템플릿