java.lang.IllegalThreadStateException : Thread already started error when using selectors with SocketChannel

标签 java android multithreading socketchannel

我正在开发一个 Android 应用程序,其中应用程序和我的服务器之间会有大量网络通信。

为了实现这一点,我使用 SocketChannelSelector 来执行非阻塞 IO。

我选择的设计是,将有一个“NetworkIOManager”线程正在等待的“BlockingQueue”。应用的其他线程将向该 BlockingQueue 发布消息,而 NetworkIOManager 将拾取这些消息并将其发送到其他线程 AsyncRequestHandlerThread

因此,NetworkIOManager线程的主要职责是从BlockingQueue中挑选消息并将其委托(delegate)给AsyncRequestHandlerThread来发送和接收请求回应。

NetworkIOManager.java 的代码:

public class NetworkIOManager implements Runnable
{
    private AsyncRequestHandlerThread handlerThread = null; 

    /*
     * 
     * some code here
     * 
     */

    private void vSendRequestUsingSocketChannel(String pTargetURL, int pTargetPort, String pRequestXML, boolean pUseSameConn) {

         // if thread is not created, initialize the thread
         if(handlerThread == null) {
             handlerThread = new AsyncRequestHandlerThread();
         }

         // create a channel to send the request and register it with the selector
         AsyncRequestHandlerThread.createChannelWithSelector(pTargetURL, pTargetPort, pRequestXML);

         // if thread is not started, start it.
         if(!handlerThread.isAlive())
              handlerThread.start();
    }
}

AsyncRequestHandlerThread 基本上为每个要发送的请求创建一个SocketChannel,使用Non-Blocking 配置,并将其注册到一个选择器与此线程关联。

AsyncRequestHandlerThread.java 的代码:

public class AsyncRequestHandlerThread extends Thread {

private static Selector selector = null;

public AsyncRequestHandlerThread() {

    if(selector ==  null)
        vSetSelector();     
}

private static void vSetSelector()
{
    try {           
        selector = Selector.open();
    } 
    catch (IOException e) {
        e.printStackTrace();            
    }
}

public static Selector getSelector()
{
    return selector;
}

public static void createChannelWithSelector(String pTargetURL, int pTargetPort, String pRequestXML) {

    try {
        SocketChannel socketChannel = SocketChannel.open();
        socketChannel.configureBlocking(false);
        socketChannel.connect(new InetSocketAddress(pTargetURL, pTargetPort));
        socketChannel.register(selector, SelectionKey.OP_CONNECT, pRequestXML);
    } 
    catch (IOException e) {
        e.printStackTrace();
    }               
}

public void run() {

    try {

        //  Wait for events with TIMEOUT : 30 secs
        while (selector.select(30000) > 0) {

            try {

                // Get list of selection keys with pending events
                Iterator<SelectionKey> iterator = selector.selectedKeys().iterator();

                // Process each key at a time
                while (iterator.hasNext()) {

                    // Get the selection key
                    SelectionKey selKey = (SelectionKey)iterator.next();

                    // Remove it from the list to indicate that it is being processed
                    iterator.remove();

                    if (selKey.isValid() && selKey.isConnectable()) {

                        // Get channel with connection request
                        SocketChannel sChannel = (SocketChannel)selKey.channel();                    
                        boolean success = sChannel.finishConnect();

                        if (success) {
                            sChannel.register(selector, SelectionKey.OP_WRITE, selKey.attachment());
                        }

                        else {

                            // An error occurred; handle it 

                            // Unregister the channel with this selector
                            selKey.cancel();

                        }
                    }

                    else if(selKey.isValid() && selKey.isWritable()) {

                        SocketChannel sChannel = (SocketChannel)selKey.channel();

                         // See Writing to a SocketChannel
                        ByteBuffer requestBuffer = null;

                        requestBuffer = ByteBuffer.wrap(selKey.attachment().toString().getBytes(Charset.forName("UTF-8")));                     
                        sChannel.write(requestBuffer);  

                        sChannel.register(selector, SelectionKey.OP_READ);
                    }
                    else if (selKey.isValid() && selKey.isReadable()) {


                        // Get channel with bytes to read
                        SocketChannel sChannel = (SocketChannel)selKey.channel();

                        // See Reading from a SocketChannel
                        ByteBuffer responseBuffer = ByteBuffer.allocate(15);


                        while(sChannel.read(responseBuffer) > 0)    {

                            String responseString = new String(responseBuffer.array(), Charset.forName("UTF-8"));
                            Log.d("STATS", responseString);
                        }   

                        sChannel.close();
                    }                               
                }
            }
            catch(IOException e)
            {
                e.printStackTrace();
            }
            catch(CancelledKeyException e) {
                e.printStackTrace();
            }
        }           
    }
    catch(IOException ex) {
        ex.printStackTrace();
    }
}   
}

我面临的问题是,当我在设备上运行应用程序时,我在 handlerThread.start(); 行上遇到了异常 java.lang.IllegalThreadStateException NetworkIOManager 类。当我调试这个时,应用程序工作正常。

我不明白问题出在哪里以及如何解决?

有什么建议吗?

最佳答案

您试图在线程退出后启动该线程。你需要重新思考你的逻辑。目前它假设只能有一个这样的线程并且它永远不会退出,但事实并非如此。

关于java.lang.IllegalThreadStateException : Thread already started error when using selectors with SocketChannel,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26989232/

相关文章:

java - 如何在 Tomcat/linux 服务器上配置 kerberos?

android - 如何在ViewPager中实现可缩放的ImageView?

android - 防止 Android 服务在解除绑定(bind)后被破坏

java - Singleton - Spring Bean 为什么不线程安全

java - 如何使用 Eclipse 启动将 native 库添加到 "java.library.path"(而不是覆盖它)

java - 如何在PHP服务器上显示android POST字符串?

java - Java 构造函数内部的多态性

android - 如何在 Android Dialog datepicker 中将默认显示设置为年份

android - 为 WebTokens 身份验证改造自定义客户端

c - 如何在posix线程之间切换?