爲什麼客戶端代碼不會終止? (我們需要在運行客戶端之前先啓動服務器程序)套接字客戶端不會終止
服務器代碼:
public class ServerSocketTest {
static final int PORT = 9999;
public static void main(String[] args) throws IOException {
final ServerSocket serverSocket = new ServerSocket(PORT);
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
try {
serverSocket.close();
} catch (IOException e) {
e.printStackTrace();
}
}
});
while (true) {
final Socket socket = serverSocket.accept();
Runnable runnable = new Runnable() {
@Override
public void run() {
System.out.println(socket);
}
};
Thread thread = new Thread(runnable);
thread.start();
}
}
}
客戶端代碼:
public class SocketClient {
public static void main(String[] args) throws UnknownHostException,
IOException {
final Socket socket = new Socket("localhost", ServerSocketTest.PORT);
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
System.out.println("waiting to close socket ");
printThread(Thread.currentThread());
try {
socket.close();
} catch (Exception e) {
e.printStackTrace();
}
}
});
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
System.out.println("waiting to exit");
printThread(Thread.currentThread());
System.exit(0);
}
});
}
static void printThread(Thread currentThread) {
System.out.println(currentThread + ": Alive=" + currentThread.isAlive()
+ ",Daemon=" + currentThread.isDaemon());
}
}
我使用Ubuntu。使用JConsole,我可以跟蹤以下線程加上其他一些RMI & JMX主題:
名稱:指向處理器 狀態:等待[email protected] 總阻塞:1總等待:2
堆棧跟蹤:
java.lang.Object.wait(Native Method)
java.lang.Object.wait(Object.java:503)
java.lang.ref.Reference$ReferenceHandler.run(Reference.java:133)
名稱:終結 統計E:對[email protected] 總等待阻止:1總等待:2
堆棧跟蹤:
java.lang.Object.wait(Native Method)
java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:135)
java.lang.ref.ReferenceQueue.remove(ReferenceQueue.java:151)
java.lang.ref.Finalizer$FinalizerThread.run(Finalizer.java:177)
名稱:信號調度 國家:RUNNABLE 總阻塞:0總等待:0
堆棧跟蹤:
名稱:DestroyJavaVM 狀態:阻塞net.SocketClient[email protected] 總等待:0總等待:1個
堆棧跟蹤:
java.lang.Object.wait(Native Method)
java.lang.Thread.join(Thread.java:1258)
java.lang.Thread.join(Thread.java:1332)
java.lang.ApplicationShutdownHooks.runHooks(ApplicationShutdownHooks.java:106)
java.lang.ApplicationShutdownHooks$1.run(ApplicationShutdownHooks.java:46)
java.lang.Shutdown.runHooks(Shutdown.java:123)
java.lang.Shutdown.sequence(Shutdown.java:167)
java.lang.Shutdown.shutdown(Shutdown.java:234)
- locked [email protected]
名稱:螺紋1(這是我添加的關閉鉤子調用System.exit) 狀態:BLOCKED on [email protected]歸屬:DestroyJavaVM 總阻塞:1等待總數:0
堆棧跟蹤:
java.lang.Shutdown.exit(Shutdown.java:212)
java.lang.Runtime.exit(Runtime.java:107)
java.lang.System.exit(System.java:960)
net.SocketClient$2.run(SocketClient.java:31)
名稱:SIGINT處理程序(這似乎當按下Ctrl + C組合被spwaned) 狀態:阻塞的java.lang。類@ 127bd04擁有者:DestroyJavaVM 總阻塞:1總等待:0
堆棧跟蹤:
java.lang.Shutdown.exit(Shutdown.java:212)
java.lang.Terminator$1.handle(Terminator.java:52)
sun.misc.Signal$1.run(Signal.java:212)
java.lang.Thread.run(Thread.java:722)
你說的「客戶端代碼不會終止」是什麼意思?看來你的客戶甚至沒有建立連接。 – 2012-07-21 07:14:42
似乎從任何關閉鉤子調用System.exit(status)都會導致該線程與DestroyJavaVM線程之間發生死鎖。在SIGINT處理程序(如果Control + C被按下)線程和DestroyJavaVM線程之間也是如此。當然,當關閉已經啓動時調用System.exit(status)幾乎沒有意義。 – 2012-07-21 13:29:56
嗯......非常有趣。你能否請你打開你的任務管理器,看看你的客戶有多少線程? – 2012-07-21 17:51:08