java.lang.IllegalThreadStateException:当使用带有SocketChannel的选择器时,线程已经启动错误

时间:2014-11-18 07:57:08

标签: java android multithreading socketchannel

我正在开发一款Android应用,其中应用与我的服务器之间会有很多网络通信。

要完成此操作,我使用SocketChannelSelector来执行非阻塞IO。

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

因此NetworkIOManager主题的主要职责是从BlockingQueue中选择邮件并将其委托给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配置并将其注册为与此线程关联的单个Selector

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();
    }
}   
}

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

我无法理解问题所在,以及如何解决?

有什么建议吗?

1 个答案:

答案 0 :(得分:1)

您尝试在退出后尝试启动该主题。你需要重新思考你的逻辑。它目前假设只有一个这样的线程并且它永远不会退出,这是不正确的。