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

use*_*525 7 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;
    }
}
Run Code Online (Sandbox Code Playgroud)

输出是:

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...
Run Code Online (Sandbox Code Playgroud)

如何x为每个线程保留单独的值,或者是否有更优化的方法来解决任务?

Rei*_*ica 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()));
Run Code Online (Sandbox Code Playgroud)

编辑:对于那些使用 1.7 的人来说,确实有一种方法可以在不使用 lambda 表达式的情况下使用 ThreadLocal。不过,您必须重写initialValue() 方法。

ThreadLocal<Integer> x = new ThreadLocal<Integer>() {
    @Override
    protected Integer initialValue() {
        return 0;
    }
};
Run Code Online (Sandbox Code Playgroud)