java线程似乎不会被释放

时间:2017-09-27 05:35:00

标签: java multithreading

我试图实现一个非常简单的回送多线程服务器 我使用了使用newFixedThreadPool创建的线程池,但看起来并发连接数固定为nThreads(传递到newFixedThreadPool)。例如,如果我将nThreads设置为3,则连接的第四个客户端无法与服务器交互。

这很奇怪,因为文档说" 创建一个线程池,重用固定数量的线程在共享的无界队列中运行。&#34 ;
由于文档还说" 如果在所有线程都处于活动状态时提交了其他任务,它们将在队列中等待,直到线程可用。"我怀疑我的线程永远不会被释放"这样它们就再也无法重复使用了。

我认为这可能是一个愚蠢的错误,但我无法弄清楚错误是什么。这是我的客户端处理程序的run()方法,我认为这与找到的代码here非常相似(下面的client只是Socket连接给客户):

@Override
public void run() {
    try(BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
        BufferedWriter out = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()))) {

        String input;
        while(true) {
            input = readLine();
            if(input == null)
                break;

            out.write(input);
            out.newLine();
            out.flush();
        }
    } catch(IOException e) {
        System.err.println(e, "Error from socket IO.");
        System.exit(1);
    }

    try {
        client.close();
    } catch(IOException e) {
        System.err.println(e, "Error when closing socket.");
        System.exit(1);
    }
    System.out.println("Client " + client.getInetAddress().getHostAddress() +
                        " closed connection.\n");
}

编辑1:我想我应该澄清一下,客户收到回复后会立即断开连接。所以线程很快就会出现。

编辑2:这里处理连接的代码(listenServerSocket):

while(true) {
    Socket client = null;
    try {
        client = listen.accept();
    } catch(IOException e) {
        System.err.println(e, "Error when waiting for connection.");
        System.exit(1);
    }
    System.out.println("New connection from client: " +
            client.getInetAddress().getHostAddress() + "\n"
    );

    threadPool.execute(new ConnectionHandler(client));
}

这是线程池初始化(在构造函数中):this.threadPool = Executors.newCachedThreadPool();

编辑3:记录消息(当nThread = 3时,所以第四个连接从未真正处理过):

New connection from client: 127.0.0.1

Client 127.0.0.1 closed connection.

New connection from client: 127.0.0.1

Client 127.0.0.1 closed connection.

New connection from client: 127.0.0.1

Client 127.0.0.1 closed connection.

New connection from client: 127.0.0.1

2 个答案:

答案 0 :(得分:2)

我没有回答为什么第四个连接悬而未决,除了说这是一个有效的代码版本......

public class Test {
    public static void main(String[] args) throws Exception {
        ServerSocket listen = new ServerSocket(9999);
        ExecutorService threadPool = Executors.newFixedThreadPool(3);
        while(true) {
            Socket client = null;
            try {
                client = listen.accept();
            } catch(IOException e) {
                System.err.println(e);
            }
            System.out.println("New connection from client: " +
                    client.getInetAddress().getHostAddress() + "\n"
            );

            threadPool.execute(new ConnectionHandler(client));
        }
    }
}

class ConnectionHandler implements Runnable {
    private Socket client;

    public ConnectionHandler(Socket client) {
        this.client = client;
    }

    @Override
    public void run() {
        try(BufferedReader in = new BufferedReader(new InputStreamReader(client.getInputStream()));
            BufferedWriter out = new BufferedWriter(new OutputStreamWriter(client.getOutputStream()))) {

            String input;
            while(true) {
                input = in.readLine();
                if(input == null)
                    break;

                out.write(input);
                out.newLine();
                out.flush();
            }
        } catch(IOException e) {
            System.err.println("Error from socket IO.");
        }

        try {
            client.close();
        } catch(IOException e) {
            System.err.println("Error when closing socket.");
        }
        System.out.println("Client " + client.getInetAddress().getHostAddress() +
                " closed connection.\n");
    }
}

我用telnet连接,回显了一些字符并断开连接。我这样做了5次。

    New connection from client: 0:0:0:0:0:0:0:1

    Client 0:0:0:0:0:0:0:1 closed connection.

    New connection from client: 0:0:0:0:0:0:0:1

    Client 0:0:0:0:0:0:0:1 closed connection.

    New connection from client: 0:0:0:0:0:0:0:1

    Client 0:0:0:0:0:0:0:1 closed connection.

    New connection from client: 0:0:0:0:0:0:0:1

    Client 0:0:0:0:0:0:0:1 closed connection.

    New connection from client: 0:0:0:0:0:0:0:1

    Client 0:0:0:0:0:0:0:1 closed connection.

唯一的区别是问题中的代码有行......

input = readLine();

我需要将其更改为

input = in.readLine();

有效。我想知道在未发布到问题的代码中是否包含静态变量或其他类型的恶作剧。

答案 1 :(得分:2)

我只是试图重现我的问题,我发现了问题(而且它确实非常愚蠢)。

在我的服务器端,我希望能够在&#34;退出&#34;时关闭服务器。在控制台中输入,所以我创建了一个 CREATE PROCEDURE [DBO].[TARGET_SIDE_PS] AS -- For error handling. DECLARE @aERROR int DECLARE @aCOUNT int -- Start transaction. BEGIN TRANSACTION -- Drop target table. IF OBJECT_ID('dbo.PML', 'U') IS NOT NULL DROP TABLE dbo.PML; -- Error catching SELECT @aERROR = @@ERROR, @aCOUNT = @@ROWCOUNT IF @aERROR<>0 BEGIN -- Error : do what is needed. -- ROLLBACK TRANSACTION RETURN 1 END SELECT * INTO dbo.PML FROM [SOURCELINKEDSERVER].[SOURCEDATABASE].[dbo].[PML] -- Error catching SELECT @aERROR = @@ERROR, @aCOUNT = @@ROWCOUNT IF @aERROR<>0 BEGIN -- Error : do what is needed. -- ROLLBACK TRANSACTION RETURN 2 END IF @aCOUNT <= 0 BEGIN -- No data: do what is needed. -- PRINT 'NO DATA !!' END COMMIT TRANSACTION RETURN 0 类(实现InputHandler)来处理服务器端输入。它看起来像这样:

Runnable

我的服务器class InputHandler implements Runnable { private Server server; InputHandler(Server server) { this.server = server; } @Override public void run() { String input = System.console().readLine(); if(input.toLowerCase().equals("exit")) server.shutdown(); else System.err.println("Invalid command. To exit enter \"exit\"."); } } 实际上是这样的:

run()

基本上每次迭代都会创建一个新的private void loop() { while(true) { threadPool.execute(new InputHandler(this)); Socket client = null; try { client = listen.accept(); } catch(Exception e) { System.err.println("Error when waiting for connection."); System.exit(1); } System.out.println("New connection from client: " + client.getInetAddress().getHostAddress() + "\n" ); threadPool.execute(new Handler(client)); } } 线程...(InputHandler)。将此代码向上移动一行将修复它......

之前我没有提及threadPool.execute(new InputHandler(this));,因为它似乎与我无关。可悲的是最终结果是它。

我很抱歉,我浪费了你们这些&#39;时间。我很抱歉。如果您愿意,请随意下载:)现在我将接受 slipperyseal 的回答。再次感谢您的帮助。