想象一下在獨立線程中啓動服務器的應用程序。在稍後的某個時間點,服務器將接收來自另一個線程的停止命令。如何實現_proper_線程安全服務器?
我看到這個實現的第一個問題是整個 Server.stop()方法是同步的。官方的Java文檔說「從同步代碼中調用其他對象的方法可能會產生活性問題」(來源:http://docs.oracle.com/javase/tutorial/essential/concurrency/locksync.html)。
第二個問題是在我看來,線程2調用Server.stop()方法線程1(服務器)的時刻可能在ServerSocket.accept()方法。這意味着ServerSocket可以被兩個線程同時訪問。
這些問題實際上是否會導致問題,或者服務器代碼是否完全正常?
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
public class Application {
public static void main(String...args){
// Thread-1 = server thread
Server server = new Server(1337);
new Thread(server).start();
// Thread-2 = any class stopping the server at some point
new Thread(new Runnable(){
@Override
public void run() {
try {
Thread.sleep(1000);
} catch (InterruptedException ignore) {
}
// Call to questionable method
server.stop();
}
}).start();
}
}
class Server implements Runnable {
protected int port;
protected ServerSocket serverSocket;
protected boolean running;
public Server(int port) {
this.port = port;
this.serverSocket = null;
this.running = true;
}
public void run() {
try {
this.serverSocket = new ServerSocket(this.port);
} catch (IOException e) {
System.out.println("Server can not be started. " + e.getMessage());
}
while (this.isRunning()) {
Socket socket = null;
try {
// 2. Server thread at blocking accept method
socket = this.serverSocket.accept();
} catch (IOException e) {
if (!this.isRunning()) {
System.out.println("Server stopped.");
return;
}
}
// Do something with the socket
System.out.println("Client connected: " + socket.getInetAddress());
}
System.out.println("Server terminated.");
}
private synchronized boolean isRunning() {
return this.running;
}
public synchronized void stop() {
if (running) {
this.running = false;
try {
// 1. Nested synchronized method call
this.serverSocket.close();
} catch (IOException e) {
System.out.println("Error closing server socket.");
}
} else {
System.out.println("Server is already stopped.");
}
}
}
服務器代碼是基於:http://tutorials.jenkov.com/java-multithreaded-servers/multithreaded-server.html