我有一个线程,其中read()
方法在循环中被调用InputStream
。当没有更多字节要读取时,流将阻塞,直到新数据到达。
如果我从其他主题调用close()
上的InputStream
,则会关闭该流,但阻止的read()
来电仍会被阻止。我假设read()
方法现在应返回值为-1
以指示流的结束,但事实并非如此。相反,它会被阻塞几分钟,直到发生tcp超时。
如何取消阻止close()
来电?
修改
显然,当阻止SocketException
调用对应的流或套接字为read()
时,常规JRE会立即抛出close()
。但是,我使用的Android Java运行时不会。
非常感谢任何关于Android环境解决方案的提示。
答案 0 :(得分:4)
只有有可用数据时才调用read()
。
做类似的事情:
while( flagBlock )
{
if( stream.available() > 0 )
{
stream.read( byteArray );
}
}
设置flagBlock
以停止阅读。
答案 1 :(得分:3)
当另一端关闭连接时,您的流将在read()上返回-1。如果你不能触发另一端关闭连接,例如通过关闭输出流,您可以关闭套接字,这将导致阻塞的read()线程中出现IOException。
您能提供一个简短的例子来重现您的问题吗?
ServerSocket ss = new ServerSocket(0);
final Socket client = new Socket("localhost", ss.getLocalPort());
Socket server = ss.accept();
Thread t = new Thread(new Runnable() {
public void run() {
int ch;
try {
while ((ch = client.getInputStream().read()) != -1)
System.out.println(ch);
} catch (SocketException se) {
System.out.println(se);
} catch (IOException e) {
e.printStackTrace();
}
}
});
t.start();
server.getOutputStream().write("hi\n".getBytes());
Thread.sleep(100);
client.close();
t.join();
server.close();
ss.close();
打印
104
105
10
java.net.SocketException: Socket closed
答案 2 :(得分:3)
在使用套接字时,请参阅Java Concurrency In Practice以获得一个非常好的系统来取消线程。它使用特殊的执行器(CancellingExecutor
)和特殊的Callable(SocketUsingTask
)。
答案 3 :(得分:2)
我们遇到了同样的问题:切换网络时也不例外(例如,在下载时从3G切换到WiFi)。
我们正在使用http://www.androidsnippets.com/download-an-http-file-to-sdcard-with-progress-notification中的代码,除非在某些情况下网络连接丢失,否则该代码工作正常。
解决方案是指定超时值,将标准设置为0(意思是:无限等待)。
HttpURLConnection c = (HttpURLConnection) u.openConnection();
c.setRequestMethod("GET");
c.setDoOutput(true);
c.setReadTimeout(1000);
c.connect();
尝试适合您的超时值。
答案 4 :(得分:1)
您可以使用java.nio
包。 NIO代表非阻塞IO。这里的呼叫(称为读和写)不会被阻止。这样你就可以关闭流了。
您可以查看here示例程序。方法:processRead
答案 5 :(得分:1)
我在三星2.3上遇到过这样的问题。从3G切换到Wifi InputStream.read()方法块时。我尝试了这个主题的所有提示。什么都没有帮助。从我的角度来看,这是特定于设备的问题,因为应该因javadoc而抛出IOException。我的解决方案是侦听android广播android.net.conn.CONNECTIVITY_CHANGE并从另一个线程关闭连接,它将在被阻塞的线程中导致IOException。
以下是代码示例:
DownloadThread.java
private volatile boolean canceled;
private volatile InputStream in;
private boolean downloadFile(final File file, final URL url, long totalSize) {
OutputStream out = null;
try {
Log.v(Common.TAG, "DownloadThread: downloading to " + file);
in = (InputStream) url.getContent();
out = new FileOutputStream(file);
return copy(out, totalSize);
} catch (Exception e) {
Log.e(Common.TAG, "DownloadThread: Exception while downloading. Returning false ", e);
return false;
} finally {
closeStream(in);
closeStream(out);
}
}
public void cancelDownloading() {
Log.e(Common.TAG, "DownloadThread: cancelDownloading ");
canceled = true;
closeStream(in); //on my device this is the only way to unblock thread
}
private boolean copy(final OutputStream out, long totalSize) throws IOException {
final int BUFFER_LENGTH = 1024;
final byte[] buffer = new byte[BUFFER_LENGTH];
long totalRead = 0;
int progress = 0;
int read;
while (!canceled && (read = in.read(buffer)) != -1) {
out.write(buffer, 0, read);
totalRead += read;
}
return !canceled;
}