编辑:
为了测试我创建了创建ExecutorService
Java应用程序的Android环境之外这个问题,提供AttackScript
(同一类)的任务,然后终止。
这将按预期100%,线程被中断,该任务被停止。
你甚至不用其Future.cancel(true)
取消任务。 ExecutorService.shutdownNow()
做这项工作。有什么在Android的Service
不知何故与线程池食堂?
即按预期工作代码:
public static void main(String[] args) {
AttackScript script = new AttackScript("http://ninjaflex.com/");
ExecutorService executor = Executors.newFixedThreadPool(5);
executor.submit(script);
executor.submit(script);
executor.submit(script);
executor.submit(script);
sleep(1300);
// Automatically interrupts threads in the pool.
executor.shutdownNow();
}
private static void sleep(long timeMilli){
try {
Thread.sleep(timeMilli);
} catch(Exception e) {
System.out.println("Error sleep()");
}
}
原帖:
我有一个Android Service
它包括ExecutorService
场,负责运行一些任务。
任务是AttackScript
类的对象。我缓存在Future
的Map<String,Future>
引用,称为任务,这样我以后可以取消它们。
Future future = executor.submit(new AttackScript(attack.getWebsite()));
tasks.put(attack.getPushId(), future);
在Service
'sonDestroy()
(被称为当用户按下通知按钮),我取消所有任务
private void cancelAllTasks() {
for (Map.Entry<String, Future> futureEntry : tasks.entrySet()) {
futureEntry.getValue().cancel(true);
}
}
然后关闭执行:
private void shutdownThreadPool() {
// https://www.baeldung.com/java-executor-service-tutorial
executor.shutdown();
try {
if (executor.awaitTermination(800, TimeUnit.MILLISECONDS))
executor.shutdownNow();
} catch (InterruptedException e) {
executor.shutdownNow();
}
}
最后,这里是AttackScript类:
public class AttackScript implements Runnable {
private static final String TAG = "AttackScript";
private URL url;
public AttackScript(String website) {
initializeUrl(website);
}
private void initializeUrl(String website) {
try {
url = new URL(website);
} catch (MalformedURLException e) {
Log.e(TAG, "Wrong url?", e);
}
}
@Override
public void run() {
while (!Thread.currentThread().isInterrupted()) {
readUrl();
}
Log.d(TAG, "Stopped requesting from " + url + " server.");
}
private void readUrl() {
InputStream in = null;
try {
in = url.openStream();
} catch (IOException e) {
Log.e(TAG, "openStream() error.", e);
} finally {
closeInputStream(in);
}
}
private void closeInputStream(InputStream in) {
try {
in.close();
Log.d(TAG, "InputStream closed for " + url);
} catch (IOException e) {
Log.e(TAG, "Error while closing the input stream.", e);
}
}
}
怪异的是,很少,像1出10,任务中断和AttackScript
的停止执行。但其他9个任务不中断,继续openStreams()上URL
s。
你有一个有效的解决方法已经回答来避免这个问题,但我会解释原因。该故障是不符合ExecutorService
但与线程的中断状态由网络图书馆静静地清除。
当你和另一个评论者发现这很可能取决于你所使用的特定设备和Android版本上。
由于Android 4.4 OkHttp
用作HttpUrlConnection
。有当每个线程中断,以及是否在InputStream
已在旧版本中被关闭之间的竞争条件。
由于close()
呼叫的一部分被最终执行该代码:
public void throwIfReached() throws IOException {
if (Thread.interrupted()) {
throw new InterruptedIOException("thread interrupted");
}
if (hasDeadline && deadlineNanoTime - System.nanoTime() <= 0) {
throw new InterruptedIOException("deadline reached");
}
}
你可以看到基础上,Thread.interrupted()
把它清除线程的中断状态,不会再设置它。
更糟糕的是,它看起来像您可以转而依靠InterruptedIOException
而关闭流时,那么你就没有机会来处理它正在悄悄进行内部处理。
使用较新的OkHttp
的版本时,你的代码示例为我工作。在以后的版本中,它看起来更加小心,以保持中断状态,它实际上按预期工作。
然而,基于一些搜索它看起来像历史上中断不会很好地与OkHttp
播放和停止他们推荐Call.cancel()
如果可能的话,而不是一个请求。
不得不寻找一个替代解决方案,我完全删除使用一个线程池,现在实现单点Thread
s,存储在Map
。
中断是,再次,从来没有发生这样的AtomicBoolean
目前正在控制线程的执行。
private AtomicBoolean stopped = new AtomicBoolean(false);
@Override
public void run() {
while (!stopped.get()) {
readUrl();
}
}
public void stopExecution() {
stopped.set(true);
}
这是一个绝望的举动,但是,到目前为止,唯一可行的。