线程安全 - 传递给线程的最终本地方法变量?

hap*_*s10 8 java concurrency multithreading final thread-safety

如果此方法的变量'commonSet'是类级别字段,则以下代码是否会导致相同的问题.如果它是类级别字段,我将不得不在同步块中包装添加设置操作,因为HashSet不是线程安全的.我应该在下面的代码中做同样的事情,因为多个线程正在添加到集合,甚至当前线程可能会继续改变集合.

public void threadCreatorFunction(final String[] args) {
    final Set<String> commonSet = new HashSet<String>();

    final Runnable runnable = new Runnable() {
        @Override
        public void run() {
            while (true) {
                commonSet.add(newValue());
            }
        }
    };

    new Thread(runnable, "T_A").start();
    new Thread(runnable, "T_B").start();
}
Run Code Online (Sandbox Code Playgroud)

'commonSet'的引用是使用final锁定的.但是在其上运行的多个线程仍然可以破坏集合中的值(它可能包含重复项?).其次,混淆是因为'commonSet'是一个方法级变量 - 它的相同引用将在调用方法的堆栈内存(threadCreatorFunction)和运行方法的堆栈内存 - 这是正确的吗?

有很多与此相关的问题:

但是,我不能看到他们强调线程安全部分这种共享/传递可变性.

Jon*_*eet 9

不,这绝对不是线程安全的.只是因为你已经在最终变量中得到它,这意味着两个线程都会看到相同的引用,这很好 - 但它不会使对象更加线程安全.

您需要同步访问或使用ConcurrentSkipListSet.


Pet*_*rey 5

一个有趣的例子.

引用commonSet是线程安全且不可变的.它位于第一个线程的堆栈和匿名Runnable类的字段中.(你可以在调试器中看到这个)

集合commonSet引用是可变的而不是线程安全的.您需要使用synchronized或Lock来使其线程安全.(或者使用线程安全集合代替)