教你利用JAVA實(shí)現(xiàn)可以自行關(guān)閉服務(wù)器的方法
JAVA實(shí)現(xiàn)可以自行關(guān)閉的服務(wù)器
普通實(shí)現(xiàn)的服務(wù)器都無法關(guān)閉自身,只有依靠操作系統(tǒng)來強(qiáng)行終止服務(wù)程序。這種強(qiáng)行終止服務(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í)行完工作隊(duì)列中現(xiàn)有的任務(wù)
executorService.shutdown();
//等待關(guān)閉線程池,每次等待的超時時間為30s
//當(dāng)使用awaitTermination時,主線程會處于一種等待的狀態(tài),等待線程池中所有的線程都運(yùn)行完畢后才繼續(xù)運(yùn)行。
//如果等待的時間超過指定的時間,但是線程池中的線程運(yùn)行完畢,那么awaitTermination()返回true。執(zhí)行分線程已結(jié)束
//如果等待的時間超過指定的時間,但是線程池中的線程未運(yùn)行完畢,那么awaitTermination()返回false。不執(zhí)行分線程已結(jié)束
//如果等待時間沒有超過指定時間,等待!
//可以用awaitTermination()方法來判斷線程池中是否有繼續(xù)運(yùn)行的線程。
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方法拋出異常,異常直接交給虛擬機(jī),虛擬機(jī)直接結(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ù)器進(jìn)行通訊)
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),等待線程池中所有的線程都運(yùn)行完畢后才繼續(xù)運(yùn)行。
//如果等待的時間超過指定的時間,但是線程池中的線程運(yùn)行完畢,那么awaitTermination()返回true。執(zhí)行分線程已結(jié)束
//如果等待的時間超過指定的時間,但是線程池中的線程未運(yùn)行完畢,那么awaitTermination()返回false。不執(zhí)行分線程已結(jié)束
//如果等待時間沒有超過指定時間,等待!
//可以用awaitTermination()方法來判斷線程池中是否有繼續(xù)運(yùn)行的線程。
while(!executorService.isTerminated())
executorService.awaitTermination(30, TimeUnit.SECONDS);
在線程池執(zhí)行了shutdown()方法后,線程池不會在接收新的任務(wù),同時該線程因?yàn)檎{(diào)用awaitTermination()方法而發(fā)生阻塞,直到線程池中所有線程的任務(wù)執(zhí)行完畢,該線程才會繼續(xù)向下
運(yùn)行結(jié)果
先運(yùn)行EchoServer,Client,AdminClient后,再開啟一客戶程序Client1,顯示Client1無法被加入線程池
- EchoServer(只顯示連接了Client,未連接Client1)

- Client

- Client2(向服務(wù)器發(fā)送消息,收到null)

- AdminClient(在Client沒有運(yùn)行結(jié)束時,被阻塞)

當(dāng)Client輸入“bye”結(jié)束運(yùn)行后,AdminClient關(guān)閉服務(wù)器
- Client類

- EchoServer類

- AdminClient類

參考Java網(wǎng)絡(luò)編程核心技術(shù)詳解
到此這篇關(guān)于教你利用JAVA實(shí)現(xiàn)可以自行關(guān)閉服務(wù)器的方法的文章就介紹到這了,更多相關(guān)JAVA自行關(guān)閉服務(wù)器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
java實(shí)現(xiàn)PPT轉(zhuǎn)化為PDF
這篇文章主要為大家詳細(xì)介紹了java實(shí)現(xiàn)PPT轉(zhuǎn)化為PDF的方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2018-06-06
JAVA面試題 簡談你對synchronized關(guān)鍵字的理解
這篇文章主要介紹了JAVA面試題 請談?wù)勀銓ychronized關(guān)鍵字的理解,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友可以參考下2019-07-07
關(guān)于@PostConstruct、afterPropertiesSet和init-method的執(zhí)行順序
這篇文章主要介紹了關(guān)于@PostConstruct、afterPropertiesSet和init-method的執(zhí)行順序,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-09-09
Spring?Cloud?OAuth2實(shí)現(xiàn)自定義token返回格式
Spring?Security?OAuth的token返回格式都是默認(rèn)的,但是往往這個格式是不適配系統(tǒng)。本文將用一個接口優(yōu)雅的實(shí)現(xiàn)?Spring?Cloud?OAuth2?自定義token返回格式,需要的可以參考一下2022-06-06
Java經(jīng)典快排思想以及快排的改進(jìn)講解
今天小編就為大家分享一篇關(guān)于Java經(jīng)典快排思想以及快排的改進(jìn)講解,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2019-01-01
Mybatis和orcale update語句中接收參數(shù)為對象的實(shí)例代碼
Mybatis的 mapper.xml 中 update 語句使用 if 標(biāo)簽判斷對像屬性是否為空值。本文重點(diǎn)給大家介紹Mybatis和orcale update語句中接收參數(shù)為對象的實(shí)例代碼,需要的朋友參考下吧2017-09-09

