我刚刚开始使用RMI,我正在尝试编写一个模拟火车预订系统的简单程序。我已经设置了基础 - 服务器,客户端和导出的远程对象。它与一个客户端连接工作正常。但是,当多个Client连接时,客户端似乎在同一个线程中执行。当我在同一台计算机上运行多个客户端或从另一台笔记本电脑连接客户端时就是这种情况。
我的印象是RMI在服务器端处理线程?如果没有,如何根据以下代码处理多个客户端连接?
以下是感兴趣的课程。
服务器.....
public class Server {
public Server() {
try {
Booking stub = (Booking) UnicastRemoteObject.exportObject(new BookingProcess(), 0);
Registry registry = LocateRegistry.getRegistry();
registry.bind("Booking", stub);
System.err.println("Server Ready");
} catch (RemoteException e) {
System.err.println("Server exception: " + e.toString());
e.printStackTrace();
} catch (AlreadyBoundException e) {
System.err.println("Server exception: " + e.toString());
e.printStackTrace();
}
}
public static void main(String[] args) {
Server server = new Server();
}
}
BookingProcess .....(我省略了processInput(String input)使用的私有方法)
public class BookingProcess implements Booking {
private static Journey dublinGalway = new Journey("Dublin to Galway");
private static Journey dublinLimerick = new Journey("Dublin to Limerick");
private static Journey dublinCork = new Journey("Dublin to Cork");
private Journey currentJourney;
private enum State {
INITIAL, JOURNEYS_DISPLAYED, JOURNEY_CHOSEN, ANOTHER_BOOKING_OFFERED, SOLD_OUT;
}
private State currentState = State.INITIAL;
public synchronized String processInput(String input) {
String output = "";
if(currentState == State.INITIAL) {
if(bookedOut()) {
output = "Sorry, there are no seats remaining on any route. Get the bus.";
currentState = State.SOLD_OUT;
}
else {
output = "Please choose a journey to book: " + "1: " + dublinGalway.getDescription() + ", 2: " + dublinLimerick.getDescription() + ", 3: " + dublinCork.getDescription();
currentState = State.JOURNEYS_DISPLAYED;
}
}
else if(currentState == State.JOURNEYS_DISPLAYED) {
output = this.processJourneyChoice(input);
}
else if(currentState == State.JOURNEY_CHOSEN) {
output = "Do you wish to confirm this booking? (y/n)";
if(input.equalsIgnoreCase("y")) {
if(bookingConfirmed()) {
output = "Thank you. Your journey from " + currentJourney.getDescription() + " is confirmed. Hit return to continue.";
//currentState = State.ANOTHER_BOOKING_OFFERED;
}
else {
output = "Sorry, but the last seat on the " + currentJourney.getDescription() + " route has just been booked by another user.";
//currentState = State.ANOTHER_BOOKING_OFFERED;
}
currentState = State.ANOTHER_BOOKING_OFFERED;
}
else if(input.equalsIgnoreCase("n")) {
output = "You have cancelled this booking. Hit return to continue.";
currentState = State.ANOTHER_BOOKING_OFFERED;
}
}
else if(currentState == State.ANOTHER_BOOKING_OFFERED) {
output = "Would you like to make another booking? (y/n)";
if(input.equalsIgnoreCase("y")) {
output = "Hit Return to continue.";
currentState = State.INITIAL;
}
else if(input.equalsIgnoreCase("n")){
output = "Goodbye.";
try {
Thread.currentThread().join(10);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
currentState = State.INITIAL;
}
}
else if(currentState == State.SOLD_OUT) {
output = "Goodbye.";
}
return output;
}
最后客户......
public class Client {
public static void main(String[] args) {
Client client = new Client();
client.runClient();
}
public void runClient() {
try {
BufferedReader consoleInput = new BufferedReader(new InputStreamReader(System.in));
Registry registry = LocateRegistry.getRegistry("localhost");
Booking stub = (Booking) registry.lookup("Booking");
String serverResponse = stub.processInput("begin");
System.out.println("Server: " + serverResponse);
while((serverResponse = stub.processInput(consoleInput.readLine())) != null) {
System.out.println(serverResponse);
if(serverResponse.equals("Goodbye.")) {
break;
}
}
} catch (Exception e) {
System.err.println("Client exception " + e.toString());
e.printStackTrace();
}
}
}
答案 0 :(得分:4)
对于RMI服务器线程,答案是它可能会也可能不会在单独的线程中运行。请参阅此处的文档:
http://docs.oracle.com/javase/6/docs/platform/rmi/spec/rmi-arch3.html
3.2远程方法调用中的线程使用
由RMI运行时调度到远程对象实现的方法可能会也可能不会在单独的线程中执行。 RMI运行时无法保证将远程对象调用映射到线程。由于同一远程对象上的远程方法调用可以并发执行,因此远程对象实现需要确保其实现是线程安全的。
您可以进行服务器端线程转储,您会看到RMI TCP连接线程ID不断变化,但是@jtahlborn注意到服务器端方法是同步的,因此它会串行执行,但不一定在单个线程中执行。 / p>
答案 1 :(得分:1)
您的服务器端processInput()
方法已同步,因此,是的,将按顺序处理呼叫。这与RMI有什么关系?
更新:
如果您希望每个客户端会话具有单独的currentState
和currentJourney
值,则需要使用RMI远程会话模式,请参阅this answer详情。