Closed. This question needs to be more focused。它当前不接受答案。
想改善这个问题吗?更新问题,使其仅关注editing this post一个问题。
4个月前关闭。
Improve this question
我有以下代码(嵌套类):
如您所见,我在那里有一个
现在发生了一件非常奇怪的事情。我添加了一些调试日志。我有一个此类的特定实例,该实例由线程B创建/初始化。此后几行,线程B还调用
几秒钟后,我看到任务正在运行,第一行调试显示
[11:08:26] [服务器线程/信息]:[xGuilds] 680任务能源25367,消耗16否
[11:08:26] [服务器线程/ INFO]:[xGuilds] 680 UPDATE能量25351,消耗16
我在
更新:我在第574行之前在unclaimAll()方法中放置了一条日志消息,但该消息没有发送...这怎么可能?
奇怪的是,仅当
我不知道这是怎么发生的,我也不知道如何重现它。它也仅在
想改善这个问题吗?更新问题,使其仅关注editing this post一个问题。
4个月前关闭。
Improve this question
我有以下代码(嵌套类):
public final class Energy {
private final int defHours = plugin.getConfiguration().defaultEnergy;
private final int resHours = plugin.getConfiguration().restoreEnergy;
private final int maxHours = plugin.getConfiguration().energyCapacity;
private BukkitTask energyTask;
private final Runnable energyCheck = () -> {
plugin.getLogger().info(id + " TASK Energy " + this.energy + ", consumption " + this.consumption);
if (this.energy == 0) {
plugin.getLogger().info(id + " TASK Energy " + this.energy + ", consumption " + this.consumption);
if (this.consumption != 0) unclaimAll(); // LINE 1178
return;
}
if ((this.energy -= this.consumption) <= 0) {
this.energy = 0;
unclaimAll();
energyTask.cancel();
energyTask = null;
}
update();
};
private int energy;
private int consumption = -1; //per minute
private Energy(final int energy) {
this.energy = energy;
}
public final void start() throws IllegalStateException {
if (isAdminGuild()) return;
plugin.getLogger().info("ENERGY START " + Guild.this.id + " " + Guild.this.name);
if (this.consumption != -1) throw new IllegalStateException("Already started");
this.consumption = members.size() * claims.size();
plugin.getLogger().info("Energy " + this.energy + ", consumption " + this.consumption);
if (consumption != 0) this.energyTask = scheduler.runTaskTimer(plugin, this.energyCheck, 100, 1200);
}
public final void update() {
if (isAdminGuild()) return;
if (this.consumption == -1) throw new IllegalStateException("Not started");
final boolean noConsumption = (this.consumption = members.size() * claims.size()) == 0;
final boolean hasEnergy = this.energy > 0;
if (noConsumption && hasEnergy) {
if (this.energyTask != null) this.energyTask.cancel();
this.energyTask = null;
this.energy = 0;
}
else if (!noConsumption && !hasEnergy) {
this.energy = this.consumption * 60 * (this.energy == -1 ? this.defHours : this.resHours);
this.energyTask = scheduler.runTaskTimer(plugin, this.energyCheck, 1, 1200);
}
plugin.getLogger().info(id + " UPDATE Energy " + this.energy + ", consumption " + this.consumption);
if (getHours() > this.maxHours) setHours(this.maxHours);
onlineMembers.forEach(p -> {
if (p != null && p.scoreboard != null) p.scoreboard.updateEnergyScore();
});
}
public final int getEnergy() {
return this.energy;
}
public final void addEnergy(final int energy) {
if (energy < 0) throw new IllegalArgumentException("Energy cannot be negative");
this.energy += energy;
update();
}
public final int getMaxEnergy() {
return isAdminGuild() || this.consumption <= 0 ? 0 : this.consumption * 60 * this.maxHours;
}
public final int getConsumption() {
return this.consumption;
}
public final int getMinutes() {
return this.consumption <= 0 ? 0 : this.energy / this.consumption;
}
public final void setMinutes(final int minutes) {
if (minutes == 0) unclaimAll();
this.energy = minutes * this.consumption;
update();
}
}
如您所见,我在那里有一个
energyCheck
Runnable,它每分钟在主线程(称为线程A)上运行。它检查energy
值是否等于零,如果是,则调用unclaimAll()
。现在发生了一件非常奇怪的事情。我添加了一些调试日志。我有一个此类的特定实例,该实例由线程B创建/初始化。此后几行,线程B还调用
start()
方法。初始化时,根据调用energy
方法时所打印的日志,为32615
赋予值start()
。 consumption
的值为16。几秒钟后,我看到任务正在运行,第一行调试显示
energy
为32615,而consumption
为16。但是,在下一秒,unclaimAll()
方法正在运行,而第二调试行则未显示。控制台显示以下内容:[11:08:26] [服务器线程/信息]:[xGuilds] 680任务能源25367,消耗16否
[11:08:26] [服务器线程/ INFO]:[xGuilds] 680 UPDATE能量25351,消耗16
我在
unclaimAll()
方法中打印RuntimeException,以查看该方法的调用位置,它指向第1178行:java.lang.RuntimeException
at eu.taigacraft.xguilds.guild.ChunkLoc.cooldown(ChunkLoc.java:43) ~[?:?]
at eu.taigacraft.xguilds.guild.ChunkLoc.unclaim(ChunkLoc.java:66) ~[?:?]
at java.lang.Iterable.forEach(Iterable.java:75) ~[?:1.8.0_232]
at eu.taigacraft.xguilds.guild.Guild.unclaimAll(Guild.java:574) ~[?:?]
at eu.taigacraft.xguilds.guild.Guild$Energy.lambda$new$0(Guild.java:1178) ~[?:?]
...
更新:我在第574行之前在unclaimAll()方法中放置了一条日志消息,但该消息没有发送...这怎么可能?
奇怪的是,仅当
energy
为0时才调用第1178行,而之前的调试日志明确指出它是32615。这怎么可能发生?我唯一想到的就是并发修改,但是正如我所说的,energyCheck
任务仅在主线程(线程A)上运行。 update()
方法是energy
可以设置为0的唯一位置,除了energyTask
之外,只有极少数其他情况可以调用update()
,这在此特定时刻极不可能发生。最奇怪的是,下次运行energyCheck
任务时,调试显示energy
为32599,这恰好是初始值减去消耗(32615-16)。在此任务的第二次运行中,就像此后的其他所有运行一样,没有调用unclaimAll()
...我不知道这是怎么发生的,我也不知道如何重现它。它也仅在
Energy
的一些特定实例中发生,并且每次都是相同的实例...任何帮助表示赞赏。 最佳答案
正如许多人在评论中所说,您没有为我们提供足够的上下文来重现此问题。
但是,对我来说很清楚,您看到的是某种竞争条件,其中在多个线程上读取或写入变量的值。
我建议您尝试将energy
和consumption
从int
更改为AtomicInteger
,看看是否可以使您获得更一致的行为。
关于java - 奇怪的整数行为/部分执行方法,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/61499899/
10-09 13:45