Java RMI 服务器端线程

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/14839955/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 17:35:12  来源:igfitidea点击:

Java RMI server side threading

javarmi

提问by user1061799

I'm just getting started with RMI and I'm trying to write a simple program that simulates a train booking system. I have the basics set up - Server, Client, and a Remote object exported. It works fine with one Client connection. However when more than 1 Client connects, the Clients seem to be executing in the same thread. This is the case when I run multiple Clients on the same machine or when I connect a Client from another laptop.

我刚刚开始使用 RMI,我正在尝试编写一个模拟火车预订系统的简单程序。我已经设置了基础 - 服务器、客户端和导出的远程对象。它适用于一个客户端连接。但是,当超过 1 个客户端连接时,客户端似乎在同一线程中执行。当我在同一台机器上运行多个客户端或从另一台笔记本电脑连接一个客户端时,就会出现这种情况。

I was under the impression that RMI handled threading on the server side? If not, how do I go about handling multiple Client connections given the code below?

我的印象是 RMI 在服务器端处理线程?如果没有,我该如何处理给定以下代码的多个客户端连接?

Here are the classes of interest.

这是感兴趣的课程。

Server.....

服务器.....

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.....(I've left out the private methods that processInput(String input) uses)

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;
    }

And finally Client......

最后是客户端......

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();
        }
    }


}

回答by vsnyc

As for as RMI server threads, the answer is that it may or may not run in a separate thread. See the documentation here:

至于作为 RMI 服务器线程,答案是它可能会或可能不会在单独的线程中运行。请参阅此处的文档:

http://docs.oracle.com/javase/6/docs/platform/rmi/spec/rmi-arch3.html

http://docs.oracle.com/javase/6/docs/platform/rmi/spec/rmi-arch3.html

3.2 Thread Usage in Remote Method Invocations

A method dispatched by the RMI runtime to a remote object implementation may or may not execute in a separate thread. The RMI runtime makes no guarantees with respect to mapping remote object invocations to threads. Since remote method invocation on the same remote object may execute concurrently, a remote object implementation needs to make sure its implementation is thread-safe.

3.2 远程方法调用中的线程使用

由 RMI 运行时分派到远程对象实现的方法可能会或可能不会在单独的线程中执行。RMI 运行时不保证将远程对象调用映射到线程。由于对同一个远程对象的远程方法调用可能并发执行,因此远程对象实现需要确保其实现是线程安全的。

You can take server side thread dumps and you would see that the RMI TCP Connection threads IDs keep changing, however as @jtahlborn noticed the server side method is synchronized so it would execute serially, not necessarily in a single thread though.

您可以进行服务器端线程转储,您会看到 RMI TCP 连接线程 ID 不断变化,但是@jtahlborn 注意到服务器端方法是同步的,因此它可以串行执行,但不一定在单个线程中执行。

回答by jtahlborn

Your server side processInput()method is synchronized, so, yes, the calls will be handled serially. what does that have to do with RMI?

您的服务器端processInput()方法是同步的,因此,是的,调用将被串行处理。这和RMI有什么关系?

UPDATE:

更新:

if you want to have separate currentStateand currentJourneyvalues for each client session, then you need to use the RMI remote session pattern, see this answerfor details.

如果您想为每个客户端会话设置单独的currentStatecurrentJourney值,那么您需要使用 RMI 远程会话模式,有关详细信息,请参阅此答案