停止DatagramSocket线程

时间:2016-11-14 12:47:49

标签: java multithreading networking

我目前正在研究一个java网络库,我正面临着DatagramSocket的问题。我有一个持续监听UDP请求的线程,每当我停止并关闭其关联的DatagramSocket时,都会有一个不会停止的线程。

以下是重现问题的代码示例:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class UDPListener implements Runnable {

    private volatile boolean isRunning;
    private volatile boolean clientClosed;
    private int port;
    private DatagramSocket client;

    public UDPListener(int listeningPort) {
        this.port = listeningPort;
    }

    public void open() throws SocketException {
        this.clientClosed = false;
        if (this.client != null) {
            this.client.close();
        }
        this.client = new DatagramSocket(this.port);
    }

    @Override
    public void run() {
        this.isRunning = true;
        this.clientClosed = false;
        DatagramPacket packet = new DatagramPacket(new byte[256], 256);
        while (this.isRunning) {

            try {
                this.client.receive(packet);
            } catch (SocketException e) {
                if (!this.clientClosed) {
                    e.printStackTrace();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        this.client.disconnect();
        System.out.println("stopped");
    }

    public void stop() {
        this.isRunning = false;
        this.clientClosed = true;
        this.client.close();
    }


    public static void main(String[] args) throws InterruptedException, SocketException {
        UDPListener t = new UDPListener(0);
        ExecutorService e = Executors.newFixedThreadPool(1);
        t.open();
        e.submit(t);
        Thread.sleep(1000);
        t.stop();
    }
}

我对Selector类有同样的问题。

我做错了什么?

1 个答案:

答案 0 :(得分:2)

您忘记包含对ExecutorService#shutdownNow()方法的调用。

我冒昧地重新编写代码并添加基本的日志记录语句,以便您可以直观地看到代码做得更好。

这是一个示例输出:

javac UDPListener.java && java UDPListener
[main] Started main application.
[main] Sleeping for 2000
[pool-1-thread-1] Starting...
[pool-1-thread-1] Opening datagram socket...
[pool-1-thread-1] Opened datagram socket.
[pool-1-thread-1] Waiting for datagrams...
[main] Slept for 2000
[main] Stopping all threads.
[pool-1-thread-1] Interrupted while waiting for datagrams.
[pool-1-thread-1] Stopped.
[main] Stopped main application.

固定代码如下:

import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.SocketException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

class UDPListener implements Runnable {

    private volatile boolean isRunning;
    private volatile boolean clientClosed;
    private int port;
    private DatagramSocket client;

    public UDPListener(int listeningPort) {
        this.port = listeningPort;
    }

    private void open() throws SocketException {
        System.out.println(getName() + " Opening datagram socket...");
        this.clientClosed = false;
        if (this.client != null) {
            this.client.close();
        }
        this.client = new DatagramSocket(this.port);
        System.out.println(getName() + " Opened datagram socket.");
    }

    @Override
    public void run() {
        System.out.println(getName() + " Starting...");
        try {
            this.open();

            this.isRunning = true;
            this.clientClosed = false;
            final DatagramPacket packet = new DatagramPacket(new byte[256], 256);

            while (this.isRunning) {
                System.out.println(getName() + " Waiting for datagrams...");
                try {
                    this.client.receive(packet);
                } catch (SocketException e) {
                    if (!this.clientClosed) {
                        e.printStackTrace();
                    }
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    System.out.println(getName() + " Interrupted while waiting for datagrams.");
                }
            }
        } catch (SocketException se) {
            se.printStackTrace();
        } finally {
            this.client.disconnect();
            System.out.println(getName() + " Stopped.");
        }
    }

    public void stop() {
        this.isRunning = false;
        this.clientClosed = true;
        this.client.close();
    }

    private static String getName() {
        return "[" + Thread.currentThread().getName() + "]";
    }


    public static void main(String[] args) throws InterruptedException, SocketException {
        System.out.println(getName() + " Started main application.");
        UDPListener t = new UDPListener(0);
        ExecutorService e = Executors.newFixedThreadPool(1);
        // t.open(); easier to debug if this call is exclusively done by UDPListener#run()
        e.submit(t);
        final int sleep = 2000;
        System.out.printf(getName() + " Sleeping for %d\n", sleep);
        Thread.sleep(sleep);
        System.out.printf(getName() + " Slept for %d\n", sleep);
        System.out.println(getName() + " Stopping all threads.");
        t.stop();
        e.shutdownNow();
        System.out.println(getName() + " Stopped main application.");
    }
}