2016-11-14 118 views
1

我目前工作的一个Java的网络图书馆,我面临着DatagramSocket的一个问题。我有一个线程持续监听UDP请求,并且每当我停止并关闭其关联的DatagramSocket时,都会有一个线程不会停止。停止一个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(); 
    } 
} 

我与选择类同样的问题。

我做错了吗?

+0

看来我是不是我的问题:(清除线程开始与执行停止(”停止“),但有一些线程我没有明确启动,继续在后台运行,留下使用的端口并阻止应用程序退出 – Maliafo

回答

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."); 
    } 
}