简体   繁体   中英

Searching for alternative to endless loop in Java

I am doing my homework which is about a chat program. It has two interfaces, one is for server and the second one is for client. Program flow is as the following:

  1. Server starts a connection on a certain port
  2. Client starts and tries to connect to server
  3. If everything is OK, they start chatting
  4. One of the terminals type "TERMINATE" conversation will be over.

This program has been originated from Deitel&Deitel 's Java How To Program 6e book. The example has only two elements for each interfaces: a displayArea (JTextArea) for displaying messages and an input (JTextField) for entering messages.

Pressing Enter will send the message to the otherside.

A piece of code of Server.java is below. It does some repetitive actions in an endless loop.

public void runServer() {
    // set up server to receive connections; process connections
    SwingUtilities.invokeLater(new Runnable() {

        public void run() 
        {
            try {

                // Step 1: Create a ServerSocket.
                String portNum = txtPort.getText();
                server = new ServerSocket(Integer.parseInt(portNum), 100);

                InetAddress ip = InetAddress.getLocalHost();
                txtServerIP.setText(ip.getHostAddress());

                while (true) {

                    try {
                        waitForConnection(); // Step 2: Wait for a connection.
                        getStreams(); // Step 3: Get input & output streams.
                        processConnection(); // Step 4: Process connection.
                    }
                    // process EOFException when client closes connection
                    catch (EOFException eofException) {
                        System.err.println("Client terminated the connection.");
                    }
                    finally {
                        closeConnection(); // Step 5: Close connection.
                        ++counter;
                    }
                } // end while
            } // end try
            // process problems with I/O
            catch (IOException ioException) {
                ioException.printStackTrace();
            }
        }
    });
} // end method runServer

It works well on original code. I have decided to add some GUI elements to the interfaces and added an Application window using Eclipse Luna 4.4.1. I have added an input for IP address and port number. Then I have added a button 'Open Connection' for Server GUI, and another button 'Connect to the Server' for Client GUI.

Now I run Server.java and it works until I click on 'Open Connection' button. Then button stays pressed eventhough I release and form does not response. After that I run Client.java and it connects to the server and gets 'Connection successful' message from server. I close Client window after sending a few messages then suddenly all the messages appear on the server window.

Now I understand that non-responsing of the Server window is because of while ( true ) loop. In other words the program is working well but cannot update interface fast enough. I want to change it with a port listener maybe, or something else which is faster or more responsive.

How can I change it?

I have changed

public void runServer() {
    // set up server to receive connections; process connections
    SwingUtilities.invokeLater(new Runnable() {...

to

public void runServer() {
    // set up server to receive connections; process connections
    SwingUtilities.invokeLater(new Thread() {...

but situation stays still.

You may access my codes

ServerGUI.java @ http://pastebin.com/pVRi6EfC

ClientGUI.java @ http://pastebin.com/HfftM159

Original codes:

Server.java @ http://pastebin.com/6Q5Z00gb

Client.java @ http://pastebin.com/uCGFGknf

The issue is that you are using SwingUtilities.invokeLater . As this answer explains, invokeLater executes the run body inside the application's primary Thread . Since your UI is also operating in this Thread , you'll need to use another method.

You'll want to put that infinite loop in a Thread and call start explicitly so it won't block your UI.

class MyChatServer extends Thread {
    public void run() {
        // the while loop
    }
}

Then, you can start up the Thread when your "Open Connection" button is pressed with:

MyChatServer server = new MyChatServer();
server.start();

Without explicitly creating a new Thread , your application will only have one Thread to work with. This Thread will be shared between the UI and any other work that you need to perform. So, when you have a bit of work (like your while(true) ) that hogs your only Thread , your UI will freeze until it is given control again.

So, by creating a new Thread , you are allowing the UI to maintain control and not freeze.

Your infinite cycle is a busy wait, which prevents your UI from refreshing. You have two problems:

  • busy wait is not the best approach
  • waiting prevents UI actualization and event-handling

Instead of busy waiting, please, look for alternatives .

Also, you should use UI in a different thread from your engine. You might want to read about swing concurrency as well.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM