【问题标题】:How to interrupt a thread if it is to open socket?如果要打开套接字,如何中断线程?
【发布时间】:2012-03-13 19:34:05
【问题描述】:

我试图关闭作为多线程服务器一部分的当前线程。 线程已准备好打开客户端可以访问的套接字。

一切正常,除非下面的代码包含在 while() 循环中。

new ServerThread(serversocket.accept(), this.Rstr, bag.numberofDatatoAcquire).start();

这是服务器的代码:

public void run() {

    System.out.println("This has been called ");   

    try{

       System.out.println("This has been tried");    
       serversocket = new ServerSocket(this.iPort);                                 

       Thread thisThread = Thread.currentThread();

       while(!thisThread.isInterrupted()){
           new ServerThread(serversocket.accept(), this.Rstr, bag.numberofDatatoAcquire).start();
           //sending socket accessed, where it will store the data and how much it will collect it.                            
           System.out.println("This has been running");                  
           Thread.sleep(10);               
       }           
    }catch(InterruptedException e){
        //why bother? it is an usual happening...lol
    }catch(IOException ioe)
    {
        System.err.println("Can't open the socket on port");               
    }
    finally{     
       System.out.println("Thread is dead and ready for change");
    }
}

这是 GUI 事件的一部分:没有“新的 ServerThread...”代码也能正常工作。

private OverWatch EW = new OverWatch(bag.iPortOrder, bag.SessionAcquisitionSavingDirectory);   

....

private void OverWatcherControl(boolean checker)
{
    if(checker)
        EW.start();  
    else
        EW.interrupt();

}

由于变量 bag.numberofDataToAcquire(公共整数类型)应该在用户需要时更改,我认为我必须停止此线程并更改变量然后再次运行此线程。我错了吗?或者我怎样才能中断这个线程?

谢谢,

【问题讨论】:

  • 当这段代码“包含在一个while循环中”时究竟会发生什么?
  • 无法中断线程,也看不到“线程已死..”的消息
  • 您是否为 server.accept 设置了超时?如果没有,它将一直等到它得到数据包;这可能是你的问题。
  • 仅供参考:我已经编辑了我的答案,以展示您如何使用 ServerSocketChannel 来接受因调用 thread.interrupt() 而被打断的问题。

标签: java multithreading interrupt


【解决方案1】:

ServerSocket.accept() 是一个不响应线程中断的阻塞调用。几乎所有java.net 阻塞调用(连接、读取、接受等)都不响应 Thread.interrupt()。这种行为是“按设计的”。

唤醒在.accept().read() 中阻塞的线程的一种方法是关闭底层套接字。

或者,您可以在 ServerSocket 上设置 SO_TIMEOUT (setSoTimeout),这将导致 .accept() 通过抛出 SocketTimeoutException 定期唤醒。您可以捕获该异常并将其用作检查线程中断状态的机会。

java.nio 包 (Java 1.4+) 提供了一个对中断响应更快的备用套接字 API。

【讨论】:

  • 我从来没有想过SocketTimeoutException!!!谢谢!!!我现在必须使用它!!!
  • 您提到这个 java.net 行为是“按设计的”。您是否有更多详细信息说明为什么要这样设计?我进行了快速搜索,但找不到这种行为背后的任何动机。
【解决方案2】:

就像使用超时或终止套接字的替代方法

伪造到套接字的新连接。这将“唤醒”accept(),然后可以使用额外的信号机制(例如标志或中断检查)(尽管必须稍微改变逻辑,以便在println 中不“撒谎”)。

我以前使用过这种方法并且效果很好:无需等待超时(甚至是排序超时)或处理另一个异常,并且套接字保持打开/有效(可能需要也可能不需要)。另一方面,我不确定在 非常长/中​​断 TCP 握手会发生什么,但这是我从未遇到过的情况 ;-)

编码愉快。

【讨论】:

  • +1 用于通过从希望它返回的线程打开连接来让阻塞调用返回。
【解决方案3】:

我最初使用serverSocket.setSoTimeout(millis) 回答它并处理SocketTimeoutException。见下文。

更好的方法是使用ServerSocketChannel,当您调用thread.interrupt() 时,它会在accept() 调用中中断,因此您根本不必旋转。所以你会做这样的事情:

ServerSocketChannel socketChannel = ServerSocketChannel.open();
socketChannel.socket().bind(new InetSocketAddress(this.iPort), 10);
...
while (! thisThread.isInterrupted()) {
    // channel accepts _are_ interrupted by the call to thread.interrupt()
    // it throws ClosedByInterruptException when interrupt() is called
    SocketChannel accepted = socketChannel.accept();
    new ServerThread(accepted.socket(), this.Rstr,
        bag.numberofDatatoAcquire).start();
}

我会稍微解释一下代码:

while(!thisThread.isInterrupted()){
   new ServerThread(serversocket.accept(), this.Rstr,
        bag.numberofDatatoAcquire).start();
   Thread.sleep(10);               
}           

我认为您的问题是serversocket.accept() 挂起 等待套接字被接受。来自accept() javadocs

侦听要与此套接字建立的连接并接受它。该方法阻塞,直到建立连接。

您需要在while 循环之前在您的套接字上设置超时。你可以使用setSoTimeout(millis)

serversocket.setSoTimeout(10000);

如果超时,这将抛出一个SocketTimeoutException。然后你就不需要Thread.sleep(10)(顺便说一句是10ms),因为睡眠将在accept()方法内完成。我推荐accept(10),因为那会非常激进。

【讨论】:

  • 好的,它挂在那里……我明白了。但是我需要 sleep() 方法,否则我不能使用中断。它说永远不会抛出 InterruptException。我希望在它接受客户之前关闭这个线程。
  • 那么你就不需要捕获了。只需将其删除。 isInterrupted() 是在线程上调用interrupt() 时设置的条件。
猜你喜欢
  • 1970-01-01
  • 2012-05-22
  • 1970-01-01
  • 2013-08-26
  • 1970-01-01
  • 2019-06-03
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多