我有一个字段int x
,应该可以同时从多个线程访问。我希望x
每个线程都有一个单独的副本,每个副本都以其原始值开头。我尝试使用volatile
关键字执行此操作,但每个新线程仍会为其他线程修改x
。
这是一个代码示例:
public class StackOverflowThread0 {
public StackOverflowThread0() {
new A().start();
}
public static void main(String[] args) {
new StackOverflowThread0();
}
volatile int x = 0;//<--keep original for each thread?
class A extends Thread {
@Override
public void run() {
try {
while (true) {
getT().start();
Thread.sleep(1000);
}
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
}
Thread getT() {
Thread t = new Thread() {
@Override
public void run() {
x++;
for (int i = 0; i < 100; i++) {
try {
System.out.println("x=" + x + " | thread id=" + Thread.currentThread().getId() + "| 100*x+x=" + (100 * x + x));
Thread.sleep(100);
} catch (InterruptedException ex) {
ex.printStackTrace();
}
}
interrupt();
}
};
return t;
}
}
输出是:
x=1 | thread id=10| 100*x+x=101
x=1 | thread id=10| 100*x+x=101
x=1 | thread id=10| 100*x+x=101
x=1 | thread id=10| 100*x+x=101
x=1 | thread id=10| 100*x+x=101
x=1 | thread id=10| 100*x+x=101
x=1 | thread id=10| 100*x+x=101
x=1 | thread id=10| 100*x+x=101
x=1 | thread id=10| 100*x+x=101
x=1 | thread id=10| 100*x+x=101 //thread 10 has x field value as 1
x=2 | thread id=11| 100*x+x=202 //thread 11 modifies x field to 2
x=2 | thread id=10| 100*x+x=202 //thread 10 lost x value as 1 :(
etc...
如何为每个线程保留单独的x
值,或者是否有更优化的方法来解决任务?
答案 0 :(得分:4)
ThreadLocal课程可以帮助您实现这一目标。它为每个访问它的线程维护一个不同的变量。换句话说,每个线程都有自己唯一的变量副本。
查看代码的以下更改:
//Initialisation of the variable. Here an initial value of zero is assigned.
ThreadLocal<Integer> x = ThreadLocal.withInitial(()-> 0);
//Incrementing the value by one:
x.set(x.get() + 1);
//Outputting the result:
System.out.println("x=" + x.get() + " | thread id="
+ Thread.currentThread().getId() + "| 100*x+x=" + (100 * x.get() + x.get()));
编辑:对于那些使用1.7的人来说,确实有一种方法可以在没有lambda表达式的情况下使用ThreadLocal。但是,您必须覆盖initialValue()方法。
ThreadLocal<Integer> x = new ThreadLocal<Integer>() {
@Override
protected Integer initialValue() {
return 0;
}
};
答案 1 :(得分:4)
替代线程本地存储,您可以将 x 变量保留在调用堆栈中。当然这取决于你如何使用 x ;你可能实际上需要你的变量在堆上。在这种情况下,你最好使用ThreadLocal。
线程都共享一个堆,但是have their own stack。
这意味着堆栈中保留的任何变量都是线程本地的。