普通實現(xiàn)的服務(wù)器都無法關(guān)閉自身,只有依靠操作系統(tǒng)來強行終止服務(wù)程序。這種強行終止服務(wù)程序的方式盡管簡單方便,但會導(dǎo)致服務(wù)器中正在執(zhí)行的任務(wù)突然中斷。如果服務(wù)器處理的任務(wù)非常重要,不允許被突然中斷,應(yīng)該由服務(wù)器自身在恰當(dāng)?shù)臅r刻關(guān)閉自己
代碼如下:
- EchoServer類
- package ShutdownServer;
- import java.io.*;
- import java.net.ServerSocket;
- import java.net.Socket;
- import java.net.SocketException;
- import java.net.SocketTimeoutException;
- import java.util.concurrent.ExecutorService;
- import java.util.concurrent.Executors;
- import java.util.concurrent.RejectedExecutionException;
- import java.util.concurrent.TimeUnit;
- public class EchoServer {
- private int port=8000;
- private ServerSocket serverSocket;
- private ExecutorService executorService; //線程池
- private final int POOL_SIZE=4; //單個CPU時線程池中工作線程的數(shù)目
- private int portForShutdown=8001; //用于監(jiān)聽關(guān)閉服務(wù)器命令的端口
- private ServerSocket serverSocketShutdown;
- private boolean isShutdown=false; //服務(wù)器是否已經(jīng)關(guān)閉
- private Thread shutdownThread=new Thread(){
- //負(fù)責(zé)關(guān)閉服務(wù)器的線程
- public void run(){
- while(!isShutdown){
- Socket socketForShutdown=null;
- try{
- socketForShutdown=serverSocketShutdown.accept();
- BufferedReader br=new BufferedReader(
- new InputStreamReader(socketForShutdown.getInputStream())
- );
- String command=br.readLine();
- if (command.equals("shutdown")){
- long beginTime=System.currentTimeMillis();
- socketForShutdown.getOutputStream().write("服務(wù)器正在關(guān)閉\r\n".getBytes());
- isShutdown=true;
- //請求關(guān)閉線程池
- //線程池不再接收新的任務(wù),但會繼續(xù)執(zhí)行完工作隊列中現(xiàn)有的任務(wù)
- executorService.shutdown();
- //等待關(guān)閉線程池,每次等待的超時時間為30s
- //當(dāng)使用awaitTermination時,主線程會處于一種等待的狀態(tài),等待線程池中所有的線程都運行完畢后才繼續(xù)運行。
- //如果等待的時間超過指定的時間,但是線程池中的線程運行完畢,那么awaitTermination()返回true。執(zhí)行分線程已結(jié)束
- //如果等待的時間超過指定的時間,但是線程池中的線程未運行完畢,那么awaitTermination()返回false。不執(zhí)行分線程已結(jié)束
- //如果等待時間沒有超過指定時間,等待!
- //可以用awaitTermination()方法來判斷線程池中是否有繼續(xù)運行的線程。
- while(!executorService.isTerminated())
- executorService.awaitTermination(30, TimeUnit.SECONDS);
- //關(guān)閉與EchoClient客戶通信的ServerSocket
- serverSocket.close();
- long endTime=System.currentTimeMillis();
- socketForShutdown.getOutputStream().write(("服務(wù)器關(guān)閉,"+"關(guān)閉服務(wù)器用了"+(endTime-beginTime)+"ms\r\n").getBytes());
- socketForShutdown.close();
- serverSocketShutdown.close();
- System.out.println("服務(wù)器關(guān)閉");
- }
- else {
- socketForShutdown.getOutputStream().write("錯誤的命令\r\n".getBytes());
- socketForShutdown.close();
- }
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- };
- public EchoServer() throws IOException {
- serverSocket=new ServerSocket(port);
- //設(shè)定等待客戶連接的超時時間為60s
- serverSocket.setSoTimeout(60000);
- serverSocketShutdown=new ServerSocket(portForShutdown);
- //創(chuàng)建線程池
- executorService= Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * POOL_SIZE);
- shutdownThread.start();
- System.out.println("服務(wù)器啟動");
- }
- public void service(){
- while(!isShutdown){
- Socket socket=null;
- try {
- //可能會拋出SocketTimeoutException和SocketException
- socket=serverSocket.accept();
- //把等待客戶發(fā)送數(shù)據(jù)的超時時間設(shè)為60s
- socket.setSoTimeout(60000);
- //可能會拋出RejectedExecutionException
- executorService.execute(new Handler(socket));
- }catch (SocketTimeoutException e){
- //不必處理等待客戶連接時出現(xiàn)的異常
- }catch (RejectedExecutionException e) {
- try {
- if (socket != null)
- socket.close();
- } catch (IOException ex) {
- return;
- }
- }catch (SocketException e){
- if (e.getMessage().indexOf("socket closed")!=-1)
- return;
- }catch (IOException e){
- e.printStackTrace();
- }
- }
- }
- public static void main(String[] args) throws IOException { //main方法拋出異常,異常直接交給虛擬機,虛擬機直接結(jié)束異常
- new EchoServer().service();
- }
- }
-
- //負(fù)責(zé)與單個客戶通信的任務(wù)
- class Handler implements Runnable{
- private Socket socket;
- public Handler(Socket socket){
- this.socket=socket;
- }
- private PrintWriter getWriter(Socket socket) throws IOException{
- OutputStream socketOut=socket.getOutputStream();
- return new PrintWriter(socketOut,true);
- }
- private BufferedReader getReader(Socket socket) throws IOException{
- InputStream socketIn=socket.getInputStream();
- return new BufferedReader(new InputStreamReader(socketIn));
- }
- public String echo(String msg){
- return "echo: "+msg;
- }
- @Override
- public void run() {
- try{
- System.out.println("New connection accepted "+socket.getInetAddress()+":"+socket.getPort());
- BufferedReader br=getReader(socket);
- PrintWriter pw=getWriter(socket);
- String msg=null;
- //接收和發(fā)送數(shù)據(jù),直到通信結(jié)束
- while((msg=br.readLine())!=null){
- System.out.println("from "+socket.getInetAddress()+":"+socket.getPort()+">"+msg);
- pw.println(echo(msg));
- if (msg.equals("bye"))
- break;
- }
- } catch (IOException e) {
- e.printStackTrace();
- }finally{
- try{
- if (socket!=null)
- socket.close();
- }catch (IOException e){
- e.printStackTrace();
- }
- }
- }
- }
- AdminClient類(負(fù)責(zé)向EchoServer發(fā)送“shutdown”命令,關(guān)閉服務(wù)器)
- package ShutdownServer;
- import java.io.BufferedReader;
- import java.io.IOException;
- import java.io.InputStreamReader;
- import java.io.OutputStream;
- import java.net.Socket;
- public class AdminClient {
- public static void main(String[] args){
- Socket socket=null;
- try{
- socket=new Socket("localhost",8001);
- //發(fā)送關(guān)閉命令
- OutputStream socketOut=socket.getOutputStream();
- //Scanner scanner=new Scanner(System.in);
- //String order=scanner.next();
- socketOut.write("shutdown\r\n".getBytes());
- //接收服務(wù)器反饋
- BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
- String msg=null;
- while ((msg=br.readLine())!=null){
- System.out.println(msg);
- }
- } catch (Exception e) {
- e.printStackTrace();
- }finally {
- try{
- if (socket!=null)
- socket.close();
- } catch (IOException e) {
- e.printStackTrace();
- }
- }
- }
- }
- Client類(客戶,與服務(wù)器進行通訊)
- package ShutdownServer;
- import java.io.*;
- import java.net.Socket;
- public class Client {
- private String host="localhost";
- private int port=8000;
- private Socket socket;
- public Client() throws IOException {
- socket=new Socket(host,port);
- }
- private PrintWriter getWriter(Socket socket) throws IOException{
- OutputStream socketOut=socket.getOutputStream();
- return new PrintWriter(socketOut,true);
- }
- private BufferedReader getReader(Socket socket) throws IOException{
- InputStream socketIn=socket.getInputStream();
- return new BufferedReader(new InputStreamReader(socketIn));
- }
- public void talk() throws IOException{
- try{
- BufferedReader br=getReader(socket);
- PrintWriter pw=getWriter(socket);
- BufferedReader localReader=new BufferedReader(new InputStreamReader(System.in));
- String msg=null;
- while((msg=localReader.readLine()) != null){
- pw.println(msg);
- System.out.println(br.readLine());
- if (msg.equals("bye")){
- break;
- }
- }
- }catch (IOException e){
- e.printStackTrace();
- }
- finally {
- try{
- socket.close();
- }catch (IOException e){
- e.printStackTrace();
- }
- }
- }
- public static void main(String args[]) throws IOException {
- new Client().talk();
- }
- }
shutdownThread線程負(fù)責(zé)關(guān)閉服務(wù)器,它一直監(jiān)聽8001端口,如果接收到了AdminClient發(fā)送的“shutdown”命令,就把isShutdown設(shè)置為true。
在關(guān)閉服務(wù)器時,我們使用了最常用的方法,先調(diào)用線程池的shutdown()方法,接著調(diào)用線程池的awaitTermination()方法。
- executorService.shutdown();
- //等待關(guān)閉線程池,每次等待的超時時間為30s
- //當(dāng)使用awaitTermination時,主線程會處于一種等待的狀態(tài),等待線程池中所有的線程都運行完畢后才繼續(xù)運行。
- //如果等待的時間超過指定的時間,但是線程池中的線程運行完畢,那么awaitTermination()返回true。執(zhí)行分線程已結(jié)束
- //如果等待的時間超過指定的時間,但是線程池中的線程未運行完畢,那么awaitTermination()返回false。不執(zhí)行分線程已結(jié)束
- //如果等待時間沒有超過指定時間,等待!
- //可以用awaitTermination()方法來判斷線程池中是否有繼續(xù)運行的線程。
- while(!executorService.isTerminated())
- executorService.awaitTermination(30, TimeUnit.SECONDS);
在線程池執(zhí)行了shutdown()方法后,線程池不會在接收新的任務(wù),同時該線程因為調(diào)用awaitTermination()方法而發(fā)生阻塞,直到線程池中所有線程的任務(wù)執(zhí)行完畢,該線程才會繼續(xù)向下
運行結(jié)果
先運行EchoServer,Client,AdminClient后,再開啟一客戶程序Client1,顯示Client1無法被加入線程池
- EchoServer(只顯示連接了Client,未連接Client1)
- Client
- Client2(向服務(wù)器發(fā)送消息,收到null)
- AdminClient(在Client沒有運行結(jié)束時,被阻塞)
當(dāng)Client輸入“bye”結(jié)束運行后,AdminClient關(guān)閉服務(wù)器
- Client類
- EchoServer類
- AdminClient類
參考Java網(wǎng)絡(luò)編程核心技術(shù)詳解
到此這篇關(guān)于教你利用JAVA實現(xiàn)可以自行關(guān)閉服務(wù)器的方法的文章就介紹到這了,更多相關(guān)JAVA自行關(guān)閉服務(wù)器內(nèi)容請搜索我們以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持我們!