日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

如何正确关闭游戏服务器

發布時間:2025/7/25 编程问答 30 豆豆
生活随笔 收集整理的這篇文章主要介紹了 如何正确关闭游戏服务器 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

一,如何正確的關閉游戲服務器

1,最簡單粗爆的方法

在Linux系統上,使用ps -aux|grep java?可以查到所有運行的java程序的pid,即進程號,然后使用kill - 9?進程號,殺死一個進程。

這樣做雖然簡單快速,但是會有一個問題,如果我們運行的服務器有緩存的數據,還沒有來得及進行持久化存儲,那么這樣操作,內存中的數據就會丟失。kill - 9是一個必殺命令,不管進程處于什么狀態,都是殺無赦,它不會給進程留下任何善后的機會。那么該如何正確的關閉游戲服務器吧?

2,優雅的關閉進程

優雅的關閉進程,就是在收到關閉進程的命令后,進程進行一些數據處理,比如:

1,不再接收連接

2,不再接收數據

3,把未持久化的數據進行持久化

4,清理一些臨時文件等

5,執行一些已經提交到線程池中但未執行的任務

? 3,Java進程如何接收進程停止命令

1,JVM?關閉鉤子

關閉鉤子本質上是一個線程(也稱為Hook線程),用來監聽JVM的關閉。通過使用Runtime的addShutdownHook(Thread hook)可以向JVM注冊一個關閉鉤子。Hook線程在JVM?正常關閉才會執行,在強制關閉時不會執行。

這個鉤子可以在一下幾種場景中被調用:

1.?程序正常退出

2.?使用System.exit()

3.?終端使用Ctrl+C觸發的中斷

4.?系統關閉

5.?OutOfMemory宕機

6.?使用Kill pid命令干掉進程(注:在使用kill -9 pid時,是不會被調用的)

對于一個JVM中注冊的多個關閉鉤子它們將會并發執行,所以JVM并不能保證它的執行順行。當所有的Hook線程執行完畢后,如果此時runFinalizersOnExit為true,那么JVM將先運行終結器,然后停止。Hook線程會延遲JVM的關閉時間,這就要求在編寫鉤子過程中必須要盡可能的減少Hook線程的執行時間。另外由于多個鉤子是并發執行的,那么很可能因為代碼不當導致出現競態條件或死鎖等問題,為了避免該問題,強烈建議在一個鉤子中執行一系列操作。

?

另外在使用關閉鉤子還要注意以下幾點:

1.?不能在鉤子調用System.exit(),否則卡住JVM的關閉過程,但是可以調用Runtime.halt()。

2.?不能再鉤子中再進行鉤子的添加和刪掉操作,否則將會拋出IllegalStateException。

3.?在System.exit()之后添加的鉤子無效。

4.?當JVM收到SIGTERM命令(比如操作系統在關閉時)后,如果鉤子線程在一定時間沒有完成,那么Hook線程可能在執行過程中被終止。

5. Hool線程中同樣會拋出異常,如果拋出異常又不處理,那么鉤子的執行序列就會被停止。

?

下面是一個簡單的示例:

?

public class T {

@SuppressWarnings("deprecation")

public static void main(String[] args) throws Exception {

//啟用退出JVM時執行Finalizer

Runtime.runFinalizersOnExit(true);

MyHook hook1 = new MyHook("Hook1");

MyHook hook2 = new MyHook("Hook2");

MyHook hook3 = new MyHook("Hook3");

?

//注冊關閉鉤子

Runtime.getRuntime().addShutdownHook(hook1);

Runtime.getRuntime().addShutdownHook(hook2);

Runtime.getRuntime().addShutdownHook(hook3);

?

//移除關閉鉤子

Runtime.getRuntime().removeShutdownHook(hook3);

?

//Main線程將在執行這句之后退出

System.out.println("Main Thread Ends.");

}

}

?

class MyHook extends Thread {

private String name;

public MyHook (String name) {

this.name = name;

setName(name);

}

public void run() {

System.out.println(name + " Ends.");

}

//重寫Finalizer,將在關閉鉤子后調用

protected void finalize() throws Throwable {

System.out.println(name + " Finalize.");

}

}

?

和(可能的)執行結果(因為JVM不保證關閉鉤子的調用順序,因此結果中的第二、三行可能出現相反的順序):

?

Main Thread Ends.

Hook2 Ends.

Hook1 Ends.

Hook3 Finalize.

Hook2 Finalize.

Hook1 Finalize.

可以看到,main函數執行完成,首先輸出的是Main Thread Ends,接下來執行關閉鉤子,輸出Hook2 Ends和Hook1 Ends。這兩行也可以證實:JVM確實不是以注冊的順序來調用關閉鉤子的。而由于hook3在調用了addShutdownHook后,接著對其調用了removeShutdownHook將其移除,于是hook3在JVM退出時沒有執行,因此沒有輸出Hook3 Ends。

另外,由于MyHook類實現了finalize方法,而main函數中第一行又通過Runtime.runFinalizersOnExit(true)打開了退出JVM時執行Finalizer的開關,于是3個hook對象的finalize方法被調用,輸出了3行Finalize。

注意,多次調用addShutdownHook來注冊同一個關閉鉤子將會拋出IllegalArgumentException:

Exception in thread "main" java.lang.IllegalArgumentException: Hook previously registered

at java.lang.ApplicationShutdownHooks.add(ApplicationShutdownHooks.java:72)

at java.lang.Runtime.addShutdownHook(Runtime.java:211)

at T.main(T.java:12)

?

另外,從JavaDoc中得知:

?

? ?Once the shutdown sequence has begun it can be stopped only by invoking the halt method, which forcibly terminates the virtual machine.

? ?Once the shutdown sequence has begun it is impossible to register a new shutdown hook or de-register a previously-registered hook. Attempting either of these operations will cause an IllegalStateException to be thrown.

?

“一旦JVM關閉流程開始,就只能通過調用halt方法來停止該流程,也不可能再注冊或移除關閉鉤子了,這些操作將導致拋出IllegalStateException”。

?

如果在關閉鉤子中關閉應用程序的公共的組件,如日志服務,或者數據庫連接等,像下面這樣:

?

Runtime.getRuntime().addShutdownHook(new Thread() {

public void run() {

try {

LogService.this.stop();

} catch (InterruptedException ignored){

//ignored

}

}

});

?

由于關閉鉤子將并發執行,因此在關閉日志時可能導致其他需要日志服務的關閉鉤子產生問題。為了避免這種情況,可以使關閉鉤子不依賴那些可能被應用程序或其他關閉鉤子關閉的服務。實現這種功能的一種方式是對所有服務使用同一個關閉鉤子(而不是每個服務使用一個不同的關閉鉤子),并且在該關閉鉤子中執行一系列的關閉操作。這確保了關閉操作在單個線程中串行執行,從而避免了在關閉操作之前出現競態條件或死鎖等問題。

二,在游戲服務器中添加關閉鉤子

?

public class ShutDownService {

private static CommonLog gameLogger = CommonLog.getInstance();

private static List<IShutDown> shutDownList = new ArrayList<>();

//注冊需要在關閉鉤子中執行的任務

public static void registShutDown(IShutDown shutDownServer) {

shutDownList.add(shutDownServer);

}

public static void startShutDownHook() {

?

Runtime.getRuntime().addShutdownHook(new Thread() {

@Override

public void run() {

gameLogger.warn(0, "開始關閉服務器,正在清理資源.....");

for (IShutDown shutDown : shutDownList) {

if (shutDown != null) {

shutDown.shutDown();

while (!shutDown.isTerminated()) {

?

}

gameLogger.warn(0, "----關閉" + shutDown.getClass().getName() + "成功----");

}

}

gameLogger.warn(0, "###---服務器關閉成功---###");

}

});

}

}

?

三,Linux腳本根據端口殺死一個進程

?

#!/bin/bash

echo "重新啟動服務"

jar_name=GameLogicServer.jar

PROCESS=`ps -ef|grep ${jar_name} |grep -v grep|grep -v PPID|awk '{ print $2}'`

for i in $PROCESS

do

?echo "######Kill the ${jar_name} process [ $i ] ########"

?

?kill -15 $i

done

?

?

while true

?do

OLD_PROCESS=`ps -ef|grep ${jar_name} |grep -v grep|grep -v PPID|awk '{ print $2}'`

if [ "${OLD_PROCESS}" = "" ]

then

echo "${PROCESS}進程已殺死成功,開始啟動新的進程"

break

else

echo "正在等待${PROCESS}進程關閉....."

sleep 1s

fi

?

?

?done

?

nohup java -server -agentpath:/usr/jprofiler9/jprofiler9/bin/linux-x64/libjprofilerti.so=port=8849,nowait -jar ${jar_name} > console.out 2>&1 &

echo "服務器啟動完成"

更多游戲技術資料請參照:游戲技術網:http://www.youxijishu.com/

轉載于:https://www.cnblogs.com/youxijishu/p/6404241.html

《新程序員》:云原生和全面數字化實踐50位技術專家共同創作,文字、視頻、音頻交互閱讀

總結

以上是生活随笔為你收集整理的如何正确关闭游戏服务器的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。