Java UDP局域网设备搜索程序抛出socket closed异常问题咨询
异常产生原因
DatagramSocket#receive()是阻塞方法,在没有收到UDP数据包时会一直挂起等待。- 按下回车键后,主线程的
System.in.read()会结束阻塞,立即执行退出逻辑:- UdpProvider中调用
provider.exit(),先给done赋值为true,随后直接调用close()关闭DatagramSocket - UdpSearcher中调用
listener.getDevicesAndClose(),同样先给done赋值为true,随后直接关闭DatagramSocket
- UdpProvider中调用
- 此时子线程大概率还阻塞在
ds.receive(receivePak)这一行,正在使用的socket被外部主动关闭,JVM就会抛出java.net.SocketException: socket closed异常。 - 额外隐藏问题:代码中
done变量没有加volatile修饰,存在多线程可见性问题:主线程修改done的值后,子线程可能感知不到变更,会继续循环执行。
解决方案
- 首先优化异常处理逻辑,将主动关闭触发的SocketException认定为正常退出场景,不需要打印错误栈,修改子线程的catch块逻辑:
catch (Exception e) { // 非主动退出场景才打印异常栈 if (!done) { e.printStackTrace(); } } - 给
done变量增加volatile修饰,保证多线程可见性,比如UdpProvider里的done修改为:
UdpSearcher的Listener类中的private volatile boolean done = false;done变量也要做相同修改。 - 可选优化:UDP场景下
receive()方法阻塞在native层,线程中断无法唤醒,主动关闭socket触发异常属于通用的退出实现方式,只要做好异常过滤即可,不需要额外调整逻辑。
内容的提问来源于stack exchange,提问作者Criwran
相关产品推荐
相关产品推荐

