App下載

JAVA自動關(guān)閉服務(wù)器的方法 代碼分享

猿友 2021-06-30 10:34:28 瀏覽數(shù) (2827)
反饋

普通實現(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類
  1. package ShutdownServer;
  2. import java.io.*;
  3. import java.net.ServerSocket;
  4. import java.net.Socket;
  5. import java.net.SocketException;
  6. import java.net.SocketTimeoutException;
  7. import java.util.concurrent.ExecutorService;
  8. import java.util.concurrent.Executors;
  9. import java.util.concurrent.RejectedExecutionException;
  10. import java.util.concurrent.TimeUnit;
  11. public class EchoServer {
  12. private int port=8000;
  13. private ServerSocket serverSocket;
  14. private ExecutorService executorService; //線程池
  15. private final int POOL_SIZE=4; //單個CPU時線程池中工作線程的數(shù)目
  16. private int portForShutdown=8001; //用于監(jiān)聽關(guān)閉服務(wù)器命令的端口
  17. private ServerSocket serverSocketShutdown;
  18. private boolean isShutdown=false; //服務(wù)器是否已經(jīng)關(guān)閉
  19. private Thread shutdownThread=new Thread(){
  20. //負(fù)責(zé)關(guān)閉服務(wù)器的線程
  21. public void run(){
  22. while(!isShutdown){
  23. Socket socketForShutdown=null;
  24. try{
  25. socketForShutdown=serverSocketShutdown.accept();
  26. BufferedReader br=new BufferedReader(
  27. new InputStreamReader(socketForShutdown.getInputStream())
  28. );
  29. String command=br.readLine();
  30. if (command.equals("shutdown")){
  31. long beginTime=System.currentTimeMillis();
  32. socketForShutdown.getOutputStream().write("服務(wù)器正在關(guān)閉\r\n".getBytes());
  33. isShutdown=true;
  34. //請求關(guān)閉線程池
  35. //線程池不再接收新的任務(wù),但會繼續(xù)執(zhí)行完工作隊列中現(xiàn)有的任務(wù)
  36. executorService.shutdown();
  37. //等待關(guān)閉線程池,每次等待的超時時間為30s
  38. //當(dāng)使用awaitTermination時,主線程會處于一種等待的狀態(tài),等待線程池中所有的線程都運行完畢后才繼續(xù)運行。
  39. //如果等待的時間超過指定的時間,但是線程池中的線程運行完畢,那么awaitTermination()返回true。執(zhí)行分線程已結(jié)束
  40. //如果等待的時間超過指定的時間,但是線程池中的線程未運行完畢,那么awaitTermination()返回false。不執(zhí)行分線程已結(jié)束
  41. //如果等待時間沒有超過指定時間,等待!
  42. //可以用awaitTermination()方法來判斷線程池中是否有繼續(xù)運行的線程。
  43. while(!executorService.isTerminated())
  44. executorService.awaitTermination(30, TimeUnit.SECONDS);
  45. //關(guān)閉與EchoClient客戶通信的ServerSocket
  46. serverSocket.close();
  47. long endTime=System.currentTimeMillis();
  48. socketForShutdown.getOutputStream().write(("服務(wù)器關(guān)閉,"+"關(guān)閉服務(wù)器用了"+(endTime-beginTime)+"ms\r\n").getBytes());
  49. socketForShutdown.close();
  50. serverSocketShutdown.close();
  51. System.out.println("服務(wù)器關(guān)閉");
  52. }
  53. else {
  54. socketForShutdown.getOutputStream().write("錯誤的命令\r\n".getBytes());
  55. socketForShutdown.close();
  56. }
  57. } catch (Exception e) {
  58. e.printStackTrace();
  59. }
  60. }
  61. }
  62. };
  63. public EchoServer() throws IOException {
  64. serverSocket=new ServerSocket(port);
  65. //設(shè)定等待客戶連接的超時時間為60s
  66. serverSocket.setSoTimeout(60000);
  67. serverSocketShutdown=new ServerSocket(portForShutdown);
  68. //創(chuàng)建線程池
  69. executorService= Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * POOL_SIZE);
  70. shutdownThread.start();
  71. System.out.println("服務(wù)器啟動");
  72. }
  73. public void service(){
  74. while(!isShutdown){
  75. Socket socket=null;
  76. try {
  77. //可能會拋出SocketTimeoutException和SocketException
  78. socket=serverSocket.accept();
  79. //把等待客戶發(fā)送數(shù)據(jù)的超時時間設(shè)為60s
  80. socket.setSoTimeout(60000);
  81. //可能會拋出RejectedExecutionException
  82. executorService.execute(new Handler(socket));
  83. }catch (SocketTimeoutException e){
  84. //不必處理等待客戶連接時出現(xiàn)的異常
  85. }catch (RejectedExecutionException e) {
  86. try {
  87. if (socket != null)
  88. socket.close();
  89. } catch (IOException ex) {
  90. return;
  91. }
  92. }catch (SocketException e){
  93. if (e.getMessage().indexOf("socket closed")!=-1)
  94. return;
  95. }catch (IOException e){
  96. e.printStackTrace();
  97. }
  98. }
  99. }
  100. public static void main(String[] args) throws IOException { //main方法拋出異常,異常直接交給虛擬機,虛擬機直接結(jié)束異常
  101. new EchoServer().service();
  102. }
  103. }
  104.  
  105. //負(fù)責(zé)與單個客戶通信的任務(wù)
  106. class Handler implements Runnable{
  107. private Socket socket;
  108. public Handler(Socket socket){
  109. this.socket=socket;
  110. }
  111. private PrintWriter getWriter(Socket socket) throws IOException{
  112. OutputStream socketOut=socket.getOutputStream();
  113. return new PrintWriter(socketOut,true);
  114. }
  115. private BufferedReader getReader(Socket socket) throws IOException{
  116. InputStream socketIn=socket.getInputStream();
  117. return new BufferedReader(new InputStreamReader(socketIn));
  118. }
  119. public String echo(String msg){
  120. return "echo: "+msg;
  121. }
  122. @Override
  123. public void run() {
  124. try{
  125. System.out.println("New connection accepted "+socket.getInetAddress()+":"+socket.getPort());
  126. BufferedReader br=getReader(socket);
  127. PrintWriter pw=getWriter(socket);
  128. String msg=null;
  129. //接收和發(fā)送數(shù)據(jù),直到通信結(jié)束
  130. while((msg=br.readLine())!=null){
  131. System.out.println("from "+socket.getInetAddress()+":"+socket.getPort()+">"+msg);
  132. pw.println(echo(msg));
  133. if (msg.equals("bye"))
  134. break;
  135. }
  136. } catch (IOException e) {
  137. e.printStackTrace();
  138. }finally{
  139. try{
  140. if (socket!=null)
  141. socket.close();
  142. }catch (IOException e){
  143. e.printStackTrace();
  144. }
  145. }
  146. }
  147. }
  • AdminClient類(負(fù)責(zé)向EchoServer發(fā)送“shutdown”命令,關(guān)閉服務(wù)器)
  1. package ShutdownServer;
  2. import java.io.BufferedReader;
  3. import java.io.IOException;
  4. import java.io.InputStreamReader;
  5. import java.io.OutputStream;
  6. import java.net.Socket;
  7. public class AdminClient {
  8. public static void main(String[] args){
  9. Socket socket=null;
  10. try{
  11. socket=new Socket("localhost",8001);
  12. //發(fā)送關(guān)閉命令
  13. OutputStream socketOut=socket.getOutputStream();
  14. //Scanner scanner=new Scanner(System.in);
  15. //String order=scanner.next();
  16. socketOut.write("shutdown\r\n".getBytes());
  17. //接收服務(wù)器反饋
  18. BufferedReader br=new BufferedReader(new InputStreamReader(socket.getInputStream()));
  19. String msg=null;
  20. while ((msg=br.readLine())!=null){
  21. System.out.println(msg);
  22. }
  23. } catch (Exception e) {
  24. e.printStackTrace();
  25. }finally {
  26. try{
  27. if (socket!=null)
  28. socket.close();
  29. } catch (IOException e) {
  30. e.printStackTrace();
  31. }
  32. }
  33. }
  34. }
  • Client類(客戶,與服務(wù)器進行通訊)
  1. package ShutdownServer;
  2. import java.io.*;
  3. import java.net.Socket;
  4. public class Client {
  5. private String host="localhost";
  6. private int port=8000;
  7. private Socket socket;
  8. public Client() throws IOException {
  9. socket=new Socket(host,port);
  10. }
  11. private PrintWriter getWriter(Socket socket) throws IOException{
  12. OutputStream socketOut=socket.getOutputStream();
  13. return new PrintWriter(socketOut,true);
  14. }
  15. private BufferedReader getReader(Socket socket) throws IOException{
  16. InputStream socketIn=socket.getInputStream();
  17. return new BufferedReader(new InputStreamReader(socketIn));
  18. }
  19. public void talk() throws IOException{
  20. try{
  21. BufferedReader br=getReader(socket);
  22. PrintWriter pw=getWriter(socket);
  23. BufferedReader localReader=new BufferedReader(new InputStreamReader(System.in));
  24. String msg=null;
  25. while((msg=localReader.readLine()) != null){
  26. pw.println(msg);
  27. System.out.println(br.readLine());
  28. if (msg.equals("bye")){
  29. break;
  30. }
  31. }
  32. }catch (IOException e){
  33. e.printStackTrace();
  34. }
  35. finally {
  36. try{
  37. socket.close();
  38. }catch (IOException e){
  39. e.printStackTrace();
  40. }
  41. }
  42. }
  43. public static void main(String args[]) throws IOException {
  44. new Client().talk();
  45. }
  46. }

shutdownThread線程負(fù)責(zé)關(guān)閉服務(wù)器,它一直監(jiān)聽8001端口,如果接收到了AdminClient發(fā)送的“shutdown”命令,就把isShutdown設(shè)置為true。

在關(guān)閉服務(wù)器時,我們使用了最常用的方法,先調(diào)用線程池的shutdown()方法,接著調(diào)用線程池的awaitTermination()方法。

  1. executorService.shutdown();
  2. //等待關(guān)閉線程池,每次等待的超時時間為30s
  3. //當(dāng)使用awaitTermination時,主線程會處于一種等待的狀態(tài),等待線程池中所有的線程都運行完畢后才繼續(xù)運行。
  4. //如果等待的時間超過指定的時間,但是線程池中的線程運行完畢,那么awaitTermination()返回true。執(zhí)行分線程已結(jié)束
  5. //如果等待的時間超過指定的時間,但是線程池中的線程未運行完畢,那么awaitTermination()返回false。不執(zhí)行分線程已結(jié)束
  6. //如果等待時間沒有超過指定時間,等待!
  7. //可以用awaitTermination()方法來判斷線程池中是否有繼續(xù)運行的線程。
  8. while(!executorService.isTerminated())
  9. 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)文章希望大家以后多多支持我們!


0 人點贊