我正纠结于这样一个问题:一个可调用的任务在顺利地工作了一天的大部分时间后,被放入Java单线程执行器中,而很明显GET从来没有被执行过。提交新任务的后续调用失败,executorservice
似乎已死。此时,生成任务的客户端将停止服务,直到流程可以重新启动,这在工作时间是不可能的。
一些背景:多个高吞吐量生产者线程将其任务放置到自己专用的单线程ExecutorService
上并立即返回。低延迟对于生产者线程非常重要。在生产者线程和执行器线程之间存在一对一的关系。每个生成器线程都需要处理这些任务。任务可以在executor线程中排队,只要它们需要执行就需要执行。交通是突飞猛进的,所以消费者总是赶上他们的生产者。
JDK:RedHat Linux上的JDK1.8.0_92
我定义我的执行人服务:
私有最终ExecutorService inboundMsgSender=Executors.NewSingleThreadExecutor();
public void onMessageFromFix(MessageEvent event, final Message message) {
log.info("submit to Executor: " + message.toString());
inboundMsgSender.submit(new Callable<Void>() {
public Void call() {
try {
onMessageFromExecutor(event, message);
} catch (Throwable e) {
log.error("error", e);
}
return null;
}
});
}
public void onMessageFromExecutor(MessageEvent event, final Message message) {
try {
log.info("call from Executor: " + message.toString());
doExpensiveLogic(message);
} catch (Exception e) {
log.error("error", e);
}
}
在正常情况下,我在日志文件中看到:
提交给执行者:4928
来自执行程序的调用:4928
没有来自Executor的后续调用,也没有例外。
无法执行可调用任务的原因是,InboundMsgSender单线程ExecutorService
中的线程被阻止,等待来自上一次调用的`DoExpensiVelogic(消息)中的FutureTask.Get()
。
这里的教训是,我假设ExecutorService的线程在阻塞时正在死亡。线程死亡由ExecutorService处理,因此我等待问题再次发生,并使用JStack进行线程转储。线程转储显示执行器服务的线程被阻塞的确切位置。
"pool-54-thread-1" #354 prio=5 os_prio=0 tid=0x567c3c00 nid=0xae4a waiting on condition [0x51125000]
java.lang.Thread.State: WAITING (parking)
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <0x69458368> (a com.aqua.api.SequentialExecutorService$ClientTaskHandle)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at java.util.concurrent.FutureTask.awaitDone(FutureTask.java:429)
at java.util.concurrent.FutureTask.get(FutureTask.java:191)
at com.aqua.jms.multiserver.impl.MultiServerJmsConnection.isConsumerConfigured(MultiServerJmsConnection.java:301)
at com.aqua.jms.multiserver.migration.MigrationConnectionWrapper.getAdministrationConnection(MigrationConnectionWrapper.java:152)
当它再次发生时我采取的步骤:
您可以从堆栈跟踪中清楚地看到线程处于活动状态,并等待FutureTask.get(),因此所需要做的就是修复未来任务或重构其中的逻辑,并使其可供我的线程直接调用。
如果我的方法被多次调用,并且它仍然在从以前的线程运行run方法,会发生什么?它会启动同样多的线程还是会等待一个线程完成后再启动另一个线程?
6.7.1.单线程执行 Android程序默认运行在单线程之下。单线程顺序执行所有的操作,这一操作完成之前,下一个操作绝不会执行。这一行为被称作“阻塞”(blocking)。 图6.8. 单线程执行 这个线程也被称作UI线程,意思是程序中用户界面的相关操作都在这里执行。除处理所有UI元素的渲染之外,事件的响应也由它负责。比如触摸屏幕、点击按钮等等。图6.8 "单线程执行"展示了在只有一个UI线程时
主要内容:1 如何使用多个线程执行一个任务,2 如何使用多个线程执行多个任务1 如何使用多个线程执行一个任务 如果需要由多个线程执行单个任务,则只有一个run()方法,例如: 1.1 多个线程执行一个任务示例1 输出结果为: 1.2 多个线程执行一个任务示例2 输出结果为: 注意:每个线程在单独的堆栈中运行。 2 如何使用多个线程执行多个任务 如果必须通过多个线程执行多个任务,请使用多个run() 方法: 2.1 多个线程执行多个任务示例1 输出结果为: 2.2 多个线程
除了接口比普通线程(例如管理)有一些优势之外,执行以下操作之间是否存在真正的内部差异(性能差异大、资源消耗……): 以及: 我只问这里的一个线索。
有一个实体A引用(多对一)实体B,从B到A有反向(映射到)引用。还有一个引用A到C,反向引用C到A。当我发出entitymanager . remove(A)then flush()时,没有生成“delete ”!但是也没有例外。就像根本没有调用remove()一样。为什么会这样?如果在remove()之前我们从反向引用B.listOfA和C.listOfA中提取A,那么“delete”就像预期的
错误:任务': app: transformClassesSusDexForDebug'执行失败。 com.android.build.api.transform.TransformException: com.android.ide.common.process.processexception: java.util.concurrent.ExecutionException: com.andr