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

1.8k views Asked by At

I am developing an Android app in which there is going to be a lot of network communication between the app and my server.

To Accomplish this, I am using SocketChannel with Selector, to do the non-blocking IO.

The design I have chosen is, that there will be a BlockingQueue on which a 'NetworkIOManager' thread will be waiting. Other threads of the app will be posting messages to that BlockingQueue and the NetworkIOManager will pickup those messages and send it to the other thread AsyncRequestHandlerThread.

Therefore the main responsibility of NetworkIOManager thread is to pick the messages from BlockingQueue and delegate them to the AsyncRequestHandlerThread to send the requests and receive the responses.

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

The AsyncRequestHandlerThread basically creates a SocketChannel for each request to be send, with a Non-Blocking configuration and registers it with a single Selector associated with this thread.

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

The issue I am facing is when I ran the application on my device I got an exception java.lang.IllegalThreadStateException on the line handlerThread.start(); in the class NetworkIOManager. When I am debugging this, the application works fine.

I am not able to understand where the problem lies and how can it be resolved ?

Any suggestions ?

1

There are 1 answers

4
user207421 On

You're trying to start the thread after it has exited. You need to rethink your logic. It presently assumes there can only be one such thread and that it never exits, which isn't true.