如何分别维护每个线程的状态

时间:2015-07-05 22:48:16

标签: java multithreading

我有一个字段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值,或者是否有更优化的方法来解决任务?

2 个答案:

答案 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

这意味着堆栈中保留的任何变量都是线程本地的。