在不同线程上访问列表的输出是什么?
What will be the output accessing a list on different threads?
我有一个 ArrayList
的 String
并且两个线程正在同时访问该列表。
以下代码段的输出结果是什么?为什么?
public static void main(String[] args) {
final ArrayList<String> list = new ArrayList<String>();
for (int i = 0; i < 100; i++) {
list.add("Number" + i);
}
new Thread() {
public void run() {
for (String s : list) {
System.out.println(s);
}
}
}.start();
new Thread() {
public void run() {
list.remove("Number5");
}
}.start();
}
我尝试使用相同的代码使 Arraylist
使用 Collections.synchronizedList(list)
同步。它仍然在抛出 java.util.ConcurrentModificationException
.
你是iterating
(在第一个线程中)和updating
(在第二个线程中)两个不同线程中的同一个list
对象,所以总是(可能)它会抛出 java.util.ConcurrentModificationException
.
在 java 中,迭代器本质上是快速失败的,因此一旦它们意识到下划线结构已被更改,它们就会失败并出现 ConcurrentModificationException
异常。
如果你想根据需要使用相同的列表对象,你可以考虑同步它,在两个线程中使用 synchronized(list)
run
方法。
public void run() {
synchronized(list) {
for (String s : list) {
System.out.println(s);
}
}
}
public void run() {
synchronized(list) {
list.remove("Number5");
}
}
我认为您应该使用 Vector
而不是 ArrayList
作为 ThreadSafe
加上使用 Iterator
来浏览您的列表。
您可以使用 syncrhonized 关键字锁定 list
对象。
Synchronized Keyword
Its overall purpose is to only allow one thread
at a time into a particular section of code thus allowing us to
protect, for example, variables or data from being corrupted by
simultaneous modifications from different threads.
所以这应该适合你:
public static void main(String[] args) {
...
new Thread() {
public void run() {
synchronized(list){
for (String s : list) {
System.out.println(s);
}
}
}
}.start();
new Thread() {
public void run() {
synchronized(list){
list.remove("Number5");
}
}
}.start();
}
注意: 这取决于你想要什么样的逻辑。 您是要在遍历列表时将其从列表中删除还是?您希望这两个任务按顺序发生吗?
synchronizedList
的 Javadoc 明确指出:
It is imperative that the user manually synchronize on the returned list when iterating over it:
List list = Collections.synchronizedList(new ArrayList());
...
synchronized (list) {
Iterator i = list.iterator(); // Must be in synchronized block
while (i.hasNext())
foo(i.next());
}
Failure to follow this advice may result in non-deterministic behavior.
因为在这段代码中,您在迭代它时从 List
中删除(在不同的线程中,但它是 List
的相同实例),ConcurrentModificationException
会被抛出。
使用 Collections.synchronizedList
,下面的代码 运行 没问题。
final List<String> list = Collections.synchronizedList(new ArrayList<String>());
for (int i = 0; i < 100; i++) {
list.add("Number" + i);
}
new Thread() {
public void run() {
synchronized (list) {
for (String s : list) {
System.out.println(s);
}
}
}
}.start();
new Thread() {
public void run() {
synchronized (list) {
list.remove("Number5");
}
}
}.start();
我有一个 ArrayList
的 String
并且两个线程正在同时访问该列表。
以下代码段的输出结果是什么?为什么?
public static void main(String[] args) {
final ArrayList<String> list = new ArrayList<String>();
for (int i = 0; i < 100; i++) {
list.add("Number" + i);
}
new Thread() {
public void run() {
for (String s : list) {
System.out.println(s);
}
}
}.start();
new Thread() {
public void run() {
list.remove("Number5");
}
}.start();
}
我尝试使用相同的代码使 Arraylist
使用 Collections.synchronizedList(list)
同步。它仍然在抛出 java.util.ConcurrentModificationException
.
你是iterating
(在第一个线程中)和updating
(在第二个线程中)两个不同线程中的同一个list
对象,所以总是(可能)它会抛出 java.util.ConcurrentModificationException
.
在 java 中,迭代器本质上是快速失败的,因此一旦它们意识到下划线结构已被更改,它们就会失败并出现 ConcurrentModificationException
异常。
如果你想根据需要使用相同的列表对象,你可以考虑同步它,在两个线程中使用 synchronized(list)
run
方法。
public void run() {
synchronized(list) {
for (String s : list) {
System.out.println(s);
}
}
}
public void run() {
synchronized(list) {
list.remove("Number5");
}
}
我认为您应该使用 Vector
而不是 ArrayList
作为 ThreadSafe
加上使用 Iterator
来浏览您的列表。
您可以使用 syncrhonized 关键字锁定 list
对象。
Synchronized Keyword
Its overall purpose is to only allow one thread at a time into a particular section of code thus allowing us to protect, for example, variables or data from being corrupted by simultaneous modifications from different threads.
所以这应该适合你:
public static void main(String[] args) {
...
new Thread() {
public void run() {
synchronized(list){
for (String s : list) {
System.out.println(s);
}
}
}
}.start();
new Thread() {
public void run() {
synchronized(list){
list.remove("Number5");
}
}
}.start();
}
注意: 这取决于你想要什么样的逻辑。 您是要在遍历列表时将其从列表中删除还是?您希望这两个任务按顺序发生吗?
synchronizedList
的 Javadoc 明确指出:
It is imperative that the user manually synchronize on the returned list when iterating over it:
List list = Collections.synchronizedList(new ArrayList()); ... synchronized (list) { Iterator i = list.iterator(); // Must be in synchronized block while (i.hasNext()) foo(i.next()); }
Failure to follow this advice may result in non-deterministic behavior.
因为在这段代码中,您在迭代它时从 List
中删除(在不同的线程中,但它是 List
的相同实例),ConcurrentModificationException
会被抛出。
使用 Collections.synchronizedList
,下面的代码 运行 没问题。
final List<String> list = Collections.synchronizedList(new ArrayList<String>());
for (int i = 0; i < 100; i++) {
list.add("Number" + i);
}
new Thread() {
public void run() {
synchronized (list) {
for (String s : list) {
System.out.println(s);
}
}
}
}.start();
new Thread() {
public void run() {
synchronized (list) {
list.remove("Number5");
}
}
}.start();