java数组线程安全
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1132507/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
java array thread-safety
提问by Jason S
Are there any concurrency problems with one thread reading from one index of an array, while another thread writes to another index of the array, as long as the indices are different?
只要索引不同,一个线程从数组的一个索引读取,而另一个线程写入数组的另一个索引是否存在并发问题?
e.g. (this example not necessarily recommended for real use, only to illustrate my point)
例如(这个例子不一定推荐用于实际使用,只是为了说明我的观点)
class Test1
{
static final private int N = 4096;
final private int[] x = new int[N];
final private AtomicInteger nwritten = new AtomicInteger(0);
// invariant:
// all values x[i] where 0 <= i < nwritten.get() are immutable
// read() is not synchronized since we want it to be fast
int read(int index) {
if (index >= nwritten.get())
throw new IllegalArgumentException();
return x[index];
}
// write() is synchronized to handle multiple writers
// (using compare-and-set techniques to avoid blocking algorithms
// is nontrivial)
synchronized void write(int x_i) {
int index = nwriting.get();
if (index >= N)
throw SomeExceptionThatIndicatesArrayIsFull();
x[index] = x_i;
// from this point forward, x[index] is fixed in stone
nwriting.set(index+1);
}
}
edit:critiquing this example is not my question, I literally just want to know if array access to one index, concurrently to access of another index, poses concurrency problems, couldn't think of a simple example.
编辑:批评这个例子不是我的问题,我真的只是想知道数组访问一个索引,同时访问另一个索引,是否会造成并发问题,想不出一个简单的例子。
采纳答案by Kathy Van Stone
While you will not get an invalid state by changing arrays as you mention, you will have the same problem that happens when two threads are viewing a non volatile integer without synchronization (see the section in the Java Tutorial on Memory Consistency Errors). Basically, the problem is that Thread 1 may write a value in space i, but there is no guarantee when (or if) Thread 2 will see the change.
虽然您不会像您提到的那样通过更改数组来获得无效状态,但是当两个线程在没有同步的情况下查看非易失性整数时,您将遇到相同的问题(请参阅 Java内存一致性错误教程中的部分)。基本上,问题在于线程 1 可能会在空间 i 中写入一个值,但无法保证线程 2 何时(或是否)会看到更改。
The class java.util.concurrent.atomic.AtomicIntegerArray
does what you want to do.
回答by kdgregory
The example has a lot of stuff that differs from the prose question.
这个例子有很多与散文问题不同的东西。
The answer to that question is that distinct elements of an array are accessed independently, so you don't need synchronization if two threads change different elements.
该问题的答案是数组的不同元素是独立访问的,因此如果两个线程更改不同的元素,则不需要同步。
However, the Java memory model makes no guarantees (that I'm aware of) that a value written by one thread will be visible to another thread, unless you synchronize access.
但是,Java 内存模型不保证(我知道)一个线程写入的值对另一个线程可见,除非您同步访问。
Depending on what you're really trying to accomplish, it's likely that java.util.concurrent
already has a class that will do it for you. And if it doesn't, I still recommend taking a look at the source code for ConcurrentHashMap
, since your code appears to be doing the same thing that it does to manage the hash table.
根据您真正想要完成的工作,很可能java.util.concurrent
已经有一个可以为您完成的课程。如果没有,我仍然建议查看 的源代码ConcurrentHashMap
,因为您的代码似乎在做与管理哈希表相同的事情。
回答by Grzegorz Oledzki
I am not really sure if synchronizing only the write
method, while leaving the read
method unsychronized would work. Not really what are all the consequences, but at least it might lead to read
method returning some values that has just been overriden by write
.
我不确定是否只同步write
方法,同时不同步read
方法会起作用。并不是所有的后果是什么,但至少它可能导致read
方法返回一些刚刚被覆盖的值write
。
回答by akarnokd
Yes, as bad cache interleaving can still happen in a multi-cpu/core environment. There are several options to avoid it:
是的,因为在多 CPU/核心环境中仍然可能发生错误的缓存交错。有几种选择可以避免它:
- Use the Unsafe Sun-private library to atomically set an element in an array (or the jsr166y added feature in Java7
- Use AtomicXYZ[] array
- Use custom object with one volatile field and have an array of that object.
- Use the ParallelArray of jsr166y addendum instead in your algorithm
- 使用 Unsafe Sun-private 库以原子方式设置数组中的元素(或 Java7 中的 jsr166y 添加功能
- 使用 AtomicXYZ[] 数组
- 使用带有一个 volatile 字段的自定义对象并拥有该对象的数组。
- 在您的算法中改用 jsr166y 附录的 ParallelArray
回答by Steve B.
Since read() is not synchronized you could have the following scenario:
由于 read() 不同步,您可能会遇到以下情况:
Thread A enters write() method
Thread A writes to nwriting = 0;
Thread B reads from nwriting =0;
Thread A increments nwriting. nwriting=1
Thread A exits write();
Since you want to guarantee that your variable addresses never conflict, what about something like (discounting array index issues):
既然你想保证你的变量地址永远不会冲突,那么(折扣数组索引问题)怎么样:
int i;
synchronized int curr(){ return i; }
synchronized int next(){ return ++i;}
int read( ) {
return values[curr()];
}
void write(int x){
values[next()]=x;
}