我正在开发一个 Android 应用程序,其中应用程序和我的服务器之间会有大量网络通信。
为了实现这一点,我使用 SocketChannel
和 Selector
来执行非阻塞 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/