我有一个宽度为 10 的固定线程池 ExecutorService,以及 100 个 Callable 的列表,每个等待 20 秒并记录它们的中断。
我在一个单独的线程中对该列表调用 invokeAll,并且几乎立即中断了该线程。 ExecutorService执行如预期中断,但Callable记录的实际中断次数远超预期10次——20-40次左右。为什么会这样,如果 ExecutorService 可以同时执行不超过 10 个线程?
完整源代码:(由于并发性,您可能需要多次运行它)
@Test
public void interrupt3() throws Exception{
int callableNum = 100;
int executorThreadNum = 10;
final AtomicInteger interruptCounter = new AtomicInteger(0);
final ExecutorService executorService = Executors.newFixedThreadPool(executorThreadNum);
final List <Callable <Object>> executeds = new ArrayList <Callable <Object>>();
for (int i = 0; i < callableNum; ++i) {
executeds.add(new Waiter(interruptCounter));
}
Thread watcher = new Thread(new Runnable() {
@Override
public void run(){
try {
executorService.invokeAll(executeds);
} catch(InterruptedException ex) {
// NOOP
}
}
});
watcher.start();
Thread.sleep(200);
watcher.interrupt();
Thread.sleep(200);
assertEquals(10, interruptCounter.get());
}
// This class just waits for 20 seconds, recording it's interrupts
private class Waiter implements Callable <Object> {
private AtomicInteger interruptCounter;
public Waiter(AtomicInteger interruptCounter){
this.interruptCounter = interruptCounter;
}
@Override
public Object call() throws Exception{
try {
Thread.sleep(20000);
} catch(InterruptedException ex) {
interruptCounter.getAndIncrement();
}
return null;
}
}
使用 WinXP 32 位、Oracle JRE 1.6.0_27 和 JUnit4
最佳答案
我不同意你应该只接收 10 次中断的假设。
Assume the CPU has 1 core.
1. Main thread starts Watcher and sleeps
2. Watcher starts and adds 100 Waiters then blocks
3. Waiter 1-10 start and sleep in sequence
4. Main wakes and interrupts Watcher then sleeps
5. Watcher cancels Waiter 1-5 then is yielded by the OS (now we have 5 interrupts)
6. Waiter 11-13 start and sleep
7. Watcher cancels Waiter 6-20 then is yielded by the OS (now we have 13 interrupts)
8. Waiter 14-20 are "started" resulting in a no-op
9. Waiter 21-24 start and sleep
....
从本质上讲,我的论点是不能保证 Watcher 线程在它必须产生时间片并允许 ExecutorService 的工作线程启动更多 Waiter 任务之前将被允许取消所有 100 个“Waiter”RunnableFuture 实例。
更新:显示来自 AbstractExecutorService
public <T> List<Future<T>> invokeAll(Collection<? extends Callable<T>> tasks)
throws InterruptedException {
if (tasks == null)
throw new NullPointerException();
List<Future<T>> futures = new ArrayList<Future<T>>(tasks.size());
boolean done = false;
try {
for (Callable<T> t : tasks) {
RunnableFuture<T> f = newTaskFor(t);
futures.add(f);
execute(f);
}
for (Future<T> f : futures) {
if (!f.isDone()) {
try {
f.get(); //If interrupted, this is where the InterruptedException will be thrown from
} catch (CancellationException ignore) {
} catch (ExecutionException ignore) {
}
}
}
done = true;
return futures;
} finally {
if (!done)
for (Future<T> f : futures)
f.cancel(true); //Specifying "true" is what allows an interrupt to be sent to the ExecutorService's worker threads
}
}
包含 f.cancel(true) 的 finally block 是将中断传播到当前正在运行的任务的时间。如您所见,这是一个紧凑的循环,但不能保证执行循环的线程能够在一个时间片内遍历 Future 的所有实例。
关于Java ExecutorService invokeAll() 中断,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7976697/
在添加一些空格以使代码更具可读性时(与上面的代码对齐),我遇到了这个:classCdefx42endendm=C.new现在这将给出“错误数量的参数”:m.x*m.x这将给出“语法错误,意外的tSTAR,期待$end”:2/m.x*m.x这里的解析器到底发生了什么?我使用Ruby1.9.2和2.1.5进行了测试。 最佳答案 *用于运算符(42*42)和参数解包(myfun*[42,42])。当你这样做时:m.x*m.x2/m.x*m.xRuby将此解释为参数解包,而不是*运算符(即乘法)。如果您不熟悉它,参数解包(有时也称为“spl
require'mechanize'agent=Mechanize.newlogin=agent.get('http://www.schoolnet.ch/DE/HomeDE.htm')agent.clicklogin.link_withtext:/Login/然后我得到Mechanize::UnsupportedSchemeError。 最佳答案 Mechanize不支持javascript但您可以将搜索字段添加到表单并为其分配搜索词并使用mechanize提交表单form=page.forms.firstform.add_fie
在几个项目中,我希望有一个类似rakeserver的rake任务,它将通过任何需要的方式开始为该应用程序提供服务。这是一个示例:task:serverdo%x{bundleexecrackup-p1234}end这行得通,但是当我准备停止它时,按Ctrl+c并没有正常关闭;它中断了Rake任务本身,它说rakeaborted!并给出堆栈跟踪。在某些情况下,我必须执行Ctrl+c两次。我可能可以用Signal.trap写一些东西来更优雅地中断它。有没有更简单的方法? 最佳答案 trap('SIGINT'){puts"Yourmessa
我有可变数量的表格和可变数量的行,我想让它们一个接一个地显示,但如果表格不适合当前页面,请将其放在下一页,然后继续。我已将表格放入事务中,以便我可以回滚然后打印它(如果高度适合当前页面),但我如何获得表格高度?我现在有这段代码pdf.transactiondopdf.table@data,:font_size=>12,:border_style=>:grid,:horizontal_padding=>10,:vertical_padding=>3,:border_width=>2,:position=>:left,:row_colors=>["FFFFFF","DDDDDD"]pdf.
我下面有一个ruby脚本,它无限地打印从1开始的数字。如何通过终端中的中断(如“Ctrl+C”或键“q”)使脚本停止无限执行?a=0while(a)putsaa+=1#thecodeshouldquitifaninterruptofacharacterisgivenend在每次迭代中,不应询问用户输入。 最佳答案 使用Kernel.trap为Ctrl-C安装信号处理程序:#!/usr/bin/rubyexit_requested=falseKernel.trap("INT"){exit_requested=true}while!
在Ruby中我有以下内容:#TrapInterruptstrap("INT")doputs"Shuttingdown..."exitend当我中断程序时,会打印以下内容(MacOSXLion):^CShuttingdown...有什么方法可以在Ruby中隐藏^C吗? 最佳答案 是否回显控制字符是您正在使用的tty的一个属性。stty-echoctl是禁用控制字符回显的Unix方法。如果您使用的是Unix-ish系统,您可以从Ruby脚本中运行此命令并获得相同的效果。 关于Ruby-在中断
为什么使用system调用创建的子进程中断ruby进程不会中断ruby进程本身?他们应该属于同一个组,所以应该都被打断。这也不适用于ruby2.0。给定ruby1.8.7补丁371、ruby1.9.3补丁392和ruby2.0补丁0:运行ruby1.8-e'system"sleep100";$?;bash中的sleep'并按⌃C只会终止对sleep100的内部调用。Ruby1.9的行为相同。虽然运行ruby2.0-e'system"sleep100";$?;sleep'中断内部命令和ruby进程本身。2.0.0-p0--编辑--阅读资源我发现处理SIGINT、S
首先,我有一个工作rails“显示”页面显示项目名称和属于该项目的条目。当使用Angular$scope显示项目名称并使用ERB中的block显示条目时,我的测试通过了。当我用AngularDirective(指令)“ng-repeat”替换条目ERB代码时,仅我的条目测试场景开始失败。有趣的是,该应用程序仍在浏览器中运行。请记住,在我看来,另一个$scope变量过去和现在仍然通过使用几乎相同的测试。工作show.html.erb(在ERB中查看的条目):Thisis{{project.details.name}}Entries打破show.html.erb(在Angular中查看的条
我在flot中绘制的图表的数据可能是不连续的-某些测量值可能会丢失。我不允许对它们进行插值-必须存在不连续性,没有值,与缺失值相邻的值之间没有联系;图表必须在休息前的最后一次测量结束,然后从休息后的第一次测量重新开始。我可以完全操作数据,我知道哪些数据丢失了,哪些数据出现在了边缘。数据以多个系列的[time,value]对的形式出现,任何系列都可以包含中断(对于中断的通信,中断通常会出现在同一时间段内。)我如何强制flot在图表中创建这样的间隙? 最佳答案 使用JavaScriptnull,像这样:[[0,0],[1,1],null
我已经创建了自己的小图像slider,为了让加载器正常工作,我必须创建一个addEventListener,然后将加载的图像附加到DOM中。但是,在这种情况下存在一个错误:当图像需要一段时间才能加载并且用户在加载之前点击它以查看下一张图像时,事件监听器仍在工作背景,当图像完全加载时,它会覆盖用户当前正在查看的内容。我的HTML:{{#eachgalleryImages}}{{#ifviewingImage}}{{>Image}}{{/if}}{{/each}}LOADING检查用户想要看到的“图像”是否是我们在each迭代中点击的图像(从而显示它):Template.ImageGall