Java 如何在多线程程序中保留线程变量的值
我有一个代码,每5秒生成一个新线程,每个线程定期打印计数器的值。它总共启动10个线程 代码如下:Java 如何在多线程程序中保留线程变量的值,java,multithreading,executorservice,Java,Multithreading,Executorservice,我有一个代码,每5秒生成一个新线程,每个线程定期打印计数器的值。它总共启动10个线程 代码如下: public static void main(String[] args) { ScheduledExecutorService task = Executors.newScheduledThreadPool(10); AtomicInteger counter = new AtomicInteger(0); int i = 0; while (i < 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) {
}
}
我希望每个线程都打印出它的原始值,例如,池-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局部变量在每个线程中保持其原始值。我能想到的方法是将线程名称到其原始值的映射存储在线程安全哈希表中。有没有更干净的方法来实现这一点?要将值绑定到特定线程,可以使用变量。 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) {
}
}
publicstaticvoidmain(字符串[]args){
ScheduledExecutorService任务=执行者。newScheduledThreadPool(10);
AtomicInteger计数器=新的AtomicInteger(0);
ThreadLocal id=ThreadLocal.withInitial(计数器::incrementAndGet);
int i=0;
而(i<10){
//睡眠5秒钟
睡眠(5);
task.scheduleAtFixedRate(()->{
字符串threadName=Thread.currentThread().getName();
System.out.println(String.format(“[%s]计数器=%d”,threadName,id.get());
},0,2,时间单位为秒);
++一,;
}
}
私有静态无效睡眠(int sleepTime){
试一试{
时间单位。秒。睡眠(睡眠时间);
}捕获(中断异常ie){
}
}
使用实例变量创建一个类,该实例变量捕获AtomicInteger的值并打印出相同的值,而不是lambda表达式。感谢您的建议。我的用例在两个方面略有不同:1。newCounter变量的初始值从主线程传递(初始值是一个随机数)2。线程正在无限期运行。因此,如果主线程中的源值发生更改,则后续运行可能会获取更改后的值。这不是我想要的。根据,ThreadLocal不应与ExecutorService一起使用。有什么想法吗?我不确定我是否关注你的担忧。你能运行我添加的代码并告诉我为什么它不能满足你的需求吗?与预期输出不同的是,pool-1-thread-X
并不总是具有计数器值X
(因为您无法控制线程调度)。但每个线程都会始终保留自己的值。以下是输出:[pool-1-thread-1]计数器=1[pool-1-thread-1]计数器=1[pool-1-thread-2]计数器=2[pool-1-thread-3]计数器=3[pool-1-thread-1]计数器=1[pool-1-thread-2]计数器=2。。。。[pool-1-thread-3]counter=3我还尝试使用ThreadLocal构造将字符串变量绑定到线程。它按预期工作。我不在乎每个线程启动时的初始值。我只需要线程在其整个生命周期中保持其初始值。再次感谢你的帮助。
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) {
}
}