title: 2019-1-14-开发笔记 Executors.newSingleThreadScheduledExecutor
tags: [java]
categories:
使用newSingleThreadScheduledExecutor作为场景执行器执行任务时,发现客户端没有返回数据,后端日志也没有显示任何异常。
于是,在调用的方法每个阶段打印前调用打log,发现方法执行到一个阶段就停止打印了。
拍卖行竞拍的代码,执行时log只打印 1.
/**
* 竞拍物品
* @param player 玩家
* @param auctionItem 拍卖品
* @param price 出价
*/
private void bidAuctionItem(Player player, AuctionItem auctionItem, int price) {
log.debug("1");
Integer auctionMoney = auctionItem.getBiddersMap().get(player.getId());
log.debug("2");
if (Objects.isNull(auctionMoney)) {
// 第一次竞拍
auctionItem.addBidder(player,price);
player.moneyChange(price);
} else {
auctionItem.addBidder(player,price);
// 减去继续竞的差价
player.moneyChange(-(price-auctionItem.getAuctionPrice()));
}
log.debug("3");
notificationManager.notifyPlayer(player,MessageFormat.format("叫价功成。当前拍卖品价格是{0}",
auctionItem.getAuctionPrice()));
log.debug("4");
}
执行这个方法的线程是一个场景执行器,
private static ThreadFactory sceneThreadFactory = new ThreadFactoryBuilder()
.setNameFormat("scene-loop-%d").build();
/** 通过一个场景一个线程处理器的方法保证每个场景的指令循序 */
ExecutorService singleThreadSchedule = Executors.newSingleThreadScheduledExecutor(sceneThreadFactory);
场景执行器开始执行任务的代码。
// 玩家在场景内则用场景的执行器执行
Optional.ofNullable(player).map(Player::getCurrentScene).ifPresent(
scene -> scene.getSingleThreadSchedule().execute(
() -> controller.handle(ctx,msg))
);
在网上查询后发现,在JDK的源码,在源码的Java doc中的发现了如下一句话:
If any execution of the task encounters an exception, subsequent executions are suppressed.Otherwise, the task will only terminate via cancellation or termination of the executor.
也就是说:
如果定时任务执行过程中遇到发生异常,则后面的任务将不再执行。
而且,异常也不会被捕获并打印信息。
我的解决方式是直接在执行任务时使用try/catch。
// 玩家在场景内则用场景的执行器执行
Optional.ofNullable(player).map(Player::getCurrentScene).ifPresent(
scene -> scene.getSingleThreadSchedule().execute(
() -> {
log.debug("{} {} 的 {} 在执行命令 {}",scene.getSingleThreadSchedule(),
scene.getName(),player.getName(),new String(msg.getContent()));
try {
controller.handle(ctx,msg);
} catch (Exception e) {
e.printStackTrace();
}
})
);
报错信息终于显示出来了。
这个问题折腾了我好久,方法执行到一半不执行我就猜测是出现了异常,但是异常没有被捕获。这件事教训我以后使用ExecutorService的实现类都要注意异常处理。