简体   繁体   中英

Concurency at a thread pool in Java

I face this problem in Java. I have a server class named MyServer and I want to implement a thread pool where each thread runs a method of MyServer when a request comes. I have created another class that implements a server pool named MultiThreadedSocketServer. The class is this:

public class MultiThreadedSocketServer {

public void startServer(MyServer s, int localport, int threadPoolSize) {
    final ExecutorService clientProcessingPool = Executors.newFixedThreadPool(threadPoolSize);

    Runnable serverTask = new Runnable() {
        @Override
        public void run() {
            try {
                ServerSocket serverSocket = new ServerSocket(localport);
                System.out.println("Waiting for clients to connect...");

                while (true) {
                    Socket clientSocket = serverSocket.accept();
                    clientProcessingPool.submit(new ClientTask(clientSocket, s));
                }
            } catch (IOException e) {
                System.err.println("Unable to process client request");
                e.printStackTrace();
            }
        }
    };
    Thread serverThread = new Thread(serverTask);
    serverThread.start();
}
}

the class named MultiThreadedSocketServer has an argument named Server s which passes it in client Task class which a thread is created. The client task class is this:

 class ClientTask implements Runnable {
    private final Socket clientSocket;
    private MyServer s;

    public ClientTask(Socket clientSocket, MyServer s) {
        this.s = s;
        this.clientSocket = clientSocket;
    }

    @Override
    public void run() {
        System.out.println("Got a client !");

        String inputLine = null;
        try {

        BufferedReader in =  new BufferedReader(new InputStreamReader(clientSocket.getInputStream()));
        // Do whatever required to process the client's request
        inputLine = in.readLine();           

        if (inputLine.equals("Bye")) {
            System.out.println("Bye");
            System.exit(0);
        }

        s.handleRequest(inputLine);

            clientSocket.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

As you can see when a request comes the handleRequest method of class MyServer is invoked. I want to make this method to run synchronized, meaning only one thread at a time to be able to run this method. Adding synchronized before the method implementation does not achieve anything.

Can anybody give me the proper way to do this? Thanks in advance for your time.

PS: I added the whole code

MyServer Class http://pastebin.com/6i2bn5jj

Multithreaded server Class http://pastebin.com/hzfLJbCS

As it is evident in main I create three requests with handleRequest with arguments Task, task2 and Bye.

The correct output would be

Waiting for clients to connect...
Got a client !
This is an input Task
Request for Task
Got a client !
This is an input task2
Request for task2
Got a client !
This is an input
Bye

But Instead the order is mixed. Sometimes Bye which shuts the server can be executed first. I want to ensure that the order is the one where the requests are created in the main.

But Instead the order is mixed. Sometimes Bye which shuts the server can be executed first. I want to ensure that the order is the one where the requests are created in the main.

You say that you want the server to handle requests in order. This is hard to ensure because you are opening up 3 sockets and writing them to the server but not waiting for any response. This is implementation dependent but I'm not sure there is any guarantee that when the client returns from doing a socket InputStream write, that the server has received the bytes. This means that from the client side, there is no guarantee that the IO completes in the order that you want.

To see if this is the problem, I would remove the System.exit(0) to see if the other lines make it, just after the "Bye" string does. Or you could put a Thread.sleep(5000); before the exit(0) .

A simple sort-of fix would be to make sure your PrintStream has auto-flush turned on. That at least will call flush on the socket but even then there are race conditions between the client and the server. If the auto-flush doesn't work then I'd have your client wait for a response from the server. So then the first client would write the first command and wait for the acknowledgement before going to the 2nd command.

In terms of your original question, locking on the server wouldn't help because of the race conditions. The "Bye" might make it first and lock the server fine.

These sorts of questions around how to synchronize the threads in a multi-threaded program really make no sense to me. The whole point of threads is that they run asynchronously in parallel and don't have to operate in any particular order. The more that you force your program to spit out the output in a particular order, the more you are arguing for writing this without any threads.

Hope this helps.

If the problem is that the bye message kills the server before other requests can be handled, one solution could be to not call System.exit(0); on bye .

The bye message could set a flag block further requests from being handled and also notify some other mechanism to call System.exit(0); when the thread pool is idle with no requests left to handle.

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