如何让此代码等待线程池中的线程可用?

How can I make this code wait until a Thread is available in the Thread Pool?

我想用 Java 练习一下网络编程和线程池。这是我写的示例代码:

/* User: koray@tugay.biz Date: 21/02/15 Time: 13:30 */

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.ArrayList;
import java.util.List;

public class MyServer {

    static List<ServerSocketThread> myThreadPool = new ArrayList<ServerSocketThread>();
    static int numberOfCurrentConnections = 0;

    public static void main(String[] args) throws IOException {

        ServerSocket serverSocket = new ServerSocket(8888);

        ServerSocketThread threadOne = new ServerSocketThread(null);
        ServerSocketThread threadTwo = new ServerSocketThread(null);

        myThreadPool.add(threadOne);
        myThreadPool.add(threadTwo);

        while (true) {
            if(numberOfCurrentConnections < 2) {
                Socket accept = serverSocket.accept();
                ServerSocketThread thread = myThreadPool.get(numberOfCurrentConnections);
                thread.setSocket(accept);
                thread.start();
                numberOfCurrentConnections++;
            } else {
                // I want to force the client to wait until a new Thread is available from the pool.
            }
        }

    }

    public static void informFinished() {
        numberOfCurrentConnections--;
    }

}

而ServerSocketThread class如下:

/* User: koray@tugay.biz Date: 21/02/15 Time: 18:14 */

import java.io.*;
import java.net.Socket;
import java.util.Scanner;

public class ServerSocketThread extends Thread {

    Socket socket;

    public ServerSocketThread(Socket accept) {
        this.socket = accept;
    }

    @Override
    public void run() {

        try {

            Scanner scanner = new Scanner(socket.getInputStream());
            String readLine;

            while (!(readLine = scanner.nextLine()).equals("bye")) {
                System.out.println(readLine);
            }

            new PrintWriter(socket.getOutputStream()).write("Bye then..");
            socket.close();
            MyServer.informFinished();

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

    }

    public void setSocket(Socket socket) {
        this.socket = socket;
    }

}

好吧,我可以像这样使用 2 个不同的终端连接到我的服务器:

Korays-MacBook-Pro:~ koraytugay$ telnet localhost 8888
Trying ::1...
Connected to localhost.
Escape character is '^]'.
laylay
bombom

并且第三个连接(如果建立)将不会被服务,因为线程池中只有 2 个线程。但是我找不到让第三个客户等到客户说 "bye" 的方法。我想做的是,在 2 个第一个连接的客户端之一断开连接后,一个线程被分配给等待的第三个客户端,但是如何?

我会回答我自己的问题,我是这样工作的:

/* User: koray@tugay.biz Date: 21/02/15 Time: 21:12 */

import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Stack;

public class MyConnectionAccepter {

    private Stack<MySocketThread> mySocketThreads = new Stack<MySocketThread>();
    private volatile int currentNumberOfConnections = 0;

    public MyConnectionAccepter() {

        MySocketThread mySocketThreadOne = new MySocketThread(this);
        MySocketThread mySocketThreadTwo = new MySocketThread(this);

        mySocketThreadOne.setDaemon(true);
        mySocketThreadTwo.setDaemon(true);

        mySocketThreadOne.start();
        mySocketThreadTwo.start();

        mySocketThreads.push(mySocketThreadOne);
        mySocketThreads.push(mySocketThreadTwo);

    }

    public void start() throws IOException {

        ServerSocket serverSocket = new ServerSocket(8888);

        while (true) {
            while (currentNumberOfConnections < 2) {
                System.out.println("Blocking now:");
                Socket accept = serverSocket.accept();
                System.out.println("Connection accepted..");
                MySocketThread mySocketThread = mySocketThreads.pop();
                mySocketThread.setSocket(accept);
                System.out.println("Incrementing connections..");
                currentNumberOfConnections++;
                System.out.println("End of while..");
            }
        }

    }

    public void informIAmDone(MySocketThread mySocketThread) {
        mySocketThreads.push(mySocketThread);
        currentNumberOfConnections--;
    }
}

/* User: koray@tugay.biz Date: 21/02/15 Time: 21:04 */

import java.io.IOException;
import java.net.Socket;
import java.util.Scanner;

public class MySocketThread extends Thread {

    private volatile Socket socket;
    MyConnectionAccepter myConnectionAccepter;

    public MySocketThread(MyConnectionAccepter myConnectionAccepter) {
        this.myConnectionAccepter = myConnectionAccepter;
    }

    @Override
    public synchronized void run() {
        System.out.println("Started...");
        serve();
    }

    public void setSocket(Socket socket) {
        this.socket = socket;
        System.out.println("Socket not null anymore..");
    }

    public void serve() {
        while(socket == null) {

        }
        while (socket != null) {
            Scanner scanner = null;
            try {
                scanner = new Scanner(socket.getInputStream());
            } catch (IOException e) {
                e.printStackTrace();
            }
            String readLine;
            while (!(readLine = scanner.nextLine()).equals("bye")) {
                System.out.println(readLine);
            }
            try {
                socket.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            socket = null;
            myConnectionAccepter.informIAmDone(this);
        }
        serve();
    }

}

和测试 Class:

/* User: koray@tugay.biz Date: 21/02/15 Time: 21:18 */

import java.io.IOException;

public class MyTestClass {

    public static void main(String[] args) throws IOException {
        MyConnectionAccepter myConnectionAccepter = new MyConnectionAccepter();
        myConnectionAccepter.start();
    }
}

我建议您按照本文所述创建一个线程池:http://tutorials.jenkov.com/java-concurrency/thread-pools.html

所以基本上除了线程池之外,您还需要维护一个任务队列。池中的每个线程都在不断地轮询任务队列中的任务。只要有任务可用(队列不为空),它就会被线程拾取并执行。在您的情况下,任务是处理客户端连接。池中的线程数是有限的(在本例中为 2)。所以在任何时候,可以同时处理的连接数是 2。只有当两个线程之一完成当前任务时,它才会选择下一个。每次收到新的连接请求时,都会向队列中添加一个新任务。

希望对您有所帮助!