如何在多线程程序中让各线程保留专属的计数器初始值
问题解决:让每个线程保留创建时的计数器初始值
你的问题核心在于lambda表达式捕获的是AtomicInteger的引用,而不是创建任务时的具体数值——每次任务执行时调用counter.get(),都会拿到这个原子变量的最新值,而不是任务创建时的初始值。
不需要用线程安全哈希表这么复杂的方案,最简洁的实现方式是利用Java对「有效final」局部变量的捕获特性:
修改后的代码
public static void main(String[] args) { ScheduledExecutorService task = Executors.newScheduledThreadPool(10); AtomicInteger counter = new AtomicInteger(0); int i = 0; while (i < 10) { // sleep 5 seconds sleep(5); // 关键:先获取当前计数器的固定值,赋值给局部变量 int currentCounter = counter.getAndIncrement(); task.scheduleAtFixedRate(() -> { String threadName = Thread.currentThread().getName(); // 直接使用捕获的固定值,不再调用counter.get() System.out.println(String.format("[%s] counter = %d", threadName, currentCounter)); }, 0, 2, TimeUnit.SECONDS); ++i; } } private static void sleep(int sleepTime) { try { TimeUnit.SECONDS.sleep(sleepTime); } catch (InterruptedException ie) { // 建议保留异常打印,避免吞掉中断信号 ie.printStackTrace(); } }
为什么这样有效?
每次循环中,currentCounter是一个全新的局部变量,它的值是任务创建时counter的当前值(getAndIncrement()会先返回当前值,再自增)。由于这个变量在赋值后不再被修改,属于Java中的「有效final」变量,lambda表达式会捕获它的副本——每个定时任务都会持有自己对应的currentCounter值,不会随着全局counter的变化而改变。
这样每个线程就会始终打印自己创建时对应的初始计数器值,完全符合你的预期输出。
内容的提问来源于stack exchange,提问作者itnovice
相关产品推荐
相关产品推荐

