【发布时间】:2014-11-18 07:57:07
【问题描述】:
我正在开发一个 Android 应用程序,在该应用程序和我的服务器之间会有大量的网络通信。
为了实现这一点,我使用SocketChannel 和Selector 来执行非阻塞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();
}
}
}
我面临的问题是,当我在设备上运行应用程序时,handlerThread.start(); 类 NetworkIOManager 的行 java.lang.IllegalThreadStateException 出现异常。当我调试它时,应用程序运行良好。
我无法理解问题出在哪里以及如何解决?
有什么建议吗?
【问题讨论】:
-
异常信息不是一目了然吗?
-
您没有正确处理
finishConnect()返回false。如果它返回false,您应该继续选择。如果它抛出异常它已经失败,你应该关闭通道,而不仅仅是取消密钥。 -
是的,我明白了,但问题是为什么
if(!handlerThread.isAlive())是true,即使线程已经在运行 -
感谢@EJP 指出这一点,我会纠正的。但我不认为这会造成我面临的问题。
-
我没说是。如果我这么认为,我会发布它作为答案。事实上,这是一条评论。
标签: java android multithreading socketchannel