【问题标题】:On server shut down AtomicBoolean chinging too late (Java)在服务器上关闭 AtomicBoolean 太晚了(Java)
【发布时间】:2020-04-11 09:28:19
【问题描述】:

我正在开发一个客户端-服务器应用程序,我想在通过套接字接收到停止消息时关闭服务器。我的服务器的代码如下所示

public class Server extends Thread {

 private AtomicBoolean running = new AtomicBoolean(true);


  public synchronized void setRunning(boolean value){
        running.set(value);
    }

 public void run(){

        while(running.get()){
                try {
                     clientSocket = serverSocket.accept();
                     //doing stuff...

                }catch (IOException e) {
                    logger.error("{} \n",e.getMessage());
                }
        }

变量 running 设置在另一个处理我的消息的类中。函数是这样写的

public synchronized void onReceive(Message message){

       if(message.equals(stopMessage)){

           server.setRunning(false);
           for(Client c : clients)
               c.shutdown();
           server.shutdown();
       }
}

我的问题是服务器中的 while 循环在将运行变量设置为 false 之前再执行一次迭代,并且服务器尝试检查套接字,即使它为空,因为连接到该套接字的客户端已经关闭(客户端是也是一个线程)。我做错了什么,但我不知道是什么。有任何想法吗?谢谢!

【问题讨论】:

  • 为什么setRunning() 是同步的?除了设置Atomic… 之外,它什么也不做……
  • 第一次尝试时我使用了一个布尔值。然后我改为 AtomicBoolean。我试过没有同步,但结果是一样的
  • accept() 块。在接受下一个连接之前,您的循环不会检查布尔值。

标签: java sockets client-server atomic


【解决方案1】:

像这样更改您的 while 循环:

while( running.get() )
{
    try( clientSocket = serverSocket.accept() ) 
    {
        if( !running.get() ) break;
        //doing stuff...

    }
    catch( SocketTimeoutException e )
    {
        continue;
    }
    catch( SocketException e )
    {
        if( !serverSocket.isClosed() ) logger.error( "{} \n", e.getMessage() );
        break;
    }
    catch( IOException e ) 
    {
        logger.error( "{} \n", e.getMessage() );
        break;
    }
}

循环在serverSocket.accept() 中等待,并且只会在传入连接或超时时继续。更改 running 不会唤醒它,因此它只会在 while 循环的下一个循环中识别更改。

并且在出现错误异常后,您不应该继续循环。即使是SocketTimeoutExceptioncontinue 也可能不正确/不充分。

【讨论】:

  • 我明白你在说什么,因为 accept() 函数是阻塞的,但是循环中的条件和中断的变化并没有解决它,它应该打破循环是很奇怪的。
  • 那个 break 无法解决它,因为函数 accept() 被迭代了,所以执行直接在 catch 中,所以在 accept() 函数之后什么都不会被执行,所以它永远不会到达 if 之后.使用 getAcquire() 也是一样的。
  • 在这种情况下,您的问题绝不是 running 标志的问题……尽管您可以在 catch 子句中再次检查它,如果为假,请按预期处理异常并执行不记录它。但这是一个肮脏的黑客......
  • 我一直在考虑在捕获中进行验证,但这不是最好的主意。我将尝试使用 InterruptedException。谢谢!
  • 这里有一个套接字泄漏。如果不打算处理接受的套接字,则必须关闭它。 Socket.accept() 不可中断。
猜你喜欢
  • 2010-11-16
  • 1970-01-01
  • 2012-07-26
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-07-03
  • 1970-01-01
相关资源
最近更新 更多