如何在多线程程序中保留线程变量的值

问题描述 投票:1回答:1

我有一个代码,每隔5秒产生一个新线程,每个线程定期打印出一个计数器的值。它最多可以启动10个线程。

这是代码:

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);
        task.scheduleAtFixedRate(() -> {
            String threadName = Thread.currentThread().getName();
            int newCounter = counter.get();
            System.out.println(String.format("[%s] counter = %d" , threadName, newCounter));
        }, 0, 2, TimeUnit.SECONDS);

        counter.getAndIncrement();
        ++i;
    }
}

private static void sleep(int sleepTime) {
    try {
        TimeUnit.SECONDS.sleep(sleepTime);
    } catch (InterruptedException ie) {

    }
}

这是输出:

[pool-1-thread-1] counter = 1
[pool-1-thread-1] counter = 1
[pool-1-thread-2] counter = 1
[pool-1-thread-3] counter = 1
[pool-1-thread-1] counter = 2
[pool-1-thread-2] counter = 2
[pool-1-thread-4] counter = 2
[pool-1-thread-5] counter = 2
[pool-1-thread-3] counter = 2
[pool-1-thread-1] counter = 3
[pool-1-thread-7] counter = 3
[pool-1-thread-6] counter = 3
[pool-1-thread-8] counter = 3
[pool-1-thread-4] counter = 3
[pool-1-thread-9] counter = 3
[pool-1-thread-5] counter = 3
[pool-1-thread-10] counter = 3
[pool-1-thread-1] counter = 4
   .......

我希望每个线程都打印出它的原始值,例如,pool-1-thread-1应该打印出0或1(取决于计数器是先获得递增还是线程首先开始),第二个线程应该发出前一个计数器+ 1持续,...如下:

[pool-1-thread-1] counter = 1
[pool-1-thread-1] counter = 1
[pool-1-thread-2] counter = 2
[pool-1-thread-3] counter = 3
[pool-1-thread-1] counter = 1
[pool-1-thread-2] counter = 2
[pool-1-thread-4] counter = 4
[pool-1-thread-5] counter = 5
[pool-1-thread-3] counter = 3
[pool-1-thread-1] counter = 1
[pool-1-thread-7] counter = 7
  .......

我的问题是如何让newCounter局部变量在每个线程中保持其原始值。我能想到的方法是在线程安全的哈希表中存储线程名称到其原始值的映射。有没有更清洁的方法来实现这一目标?谢谢

java multithreading executorservice
1个回答
1
投票

要将值绑定到特定线程,可以使用ThreadLocal变量。 javadoc中的ThreadId示例类可以很容易地适应您的用例。

public static void main(String[] args) {
    ScheduledExecutorService task = Executors.newScheduledThreadPool(10);
    AtomicInteger counter = new AtomicInteger(0);
    ThreadLocal<Integer> id = ThreadLocal.withInitial(counter::incrementAndGet);
    int i = 0;
    while (i < 10) {
        // sleep 5 seconds
        sleep(5);
        task.scheduleAtFixedRate(() -> {
            String threadName = Thread.currentThread().getName();
            System.out.println(String.format("[%s] counter = %d" , threadName, id.get()));
        }, 0, 2, TimeUnit.SECONDS);

        ++i;
    }
}

private static void sleep(int sleepTime) {
    try {
        TimeUnit.SECONDS.sleep(sleepTime);
    } catch (InterruptedException ie) {

    }
}
© www.soinside.com 2019 - 2024. All rights reserved.