博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java中 CopyOnWriteArrayList 的使用
阅读量:4690 次
发布时间:2019-06-09

本文共 3002 字,大约阅读时间需要 10 分钟。

java中,List在遍历的时候,如果被修改了会抛出java.util.ConcurrentModificationException错误。

看如下代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
import
java.util.ArrayList;
import
java.util.List;
 
public
class
Resource3 {
 
    
public
static
void
main(String[] args)
throws
InterruptedException {
        
List<String> a =
new
ArrayList<String>();
        
a.add(
"a"
);
        
a.add(
"b"
);
        
a.add(
"c"
);
        
final
ArrayList<String> list =
new
ArrayList<String>(
                
a);
        
Thread t =
new
Thread(
new
Runnable() {
            
int
count = -
1
;
 
            
@Override
            
public
void
run() {
                
while
(
true
) {
                    
list.add(count++ +
""
);
                
}
            
}
        
});
        
t.setDaemon(
true
);
        
t.start();
        
Thread.currentThread().sleep(
3
);
        
for
(String s : list) {
            
System.out.println(s);
        
}
    
}
}

这段代码运行的时候就会抛出java.util.ConcurrentModificationException错误。这是因为主线程在遍历list的时候,子线程在向list中添加元素。

那么有没有办法在遍历一个list的时候,还向list中添加元素呢?办法是有的。就是java concurrent包中的CopyOnWriteArrayList。

先解释下CopyOnWriteArrayList类。

CopyOnWriteArrayList类最大的特点就是,在对其实例进行修改操作(add/remove等)会新建一个数据并修改,修改完毕之后,再将原来的引用指向新的数组。这样,修改过程没有修改原来的数组。也就没有了ConcurrentModificationException错误。

看下面的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
import
java.util.ArrayList;
import
java.util.List;
import
java.util.concurrent.CopyOnWriteArrayList;
 
public
class
Resource3 {
 
    
public
static
void
main(String[] args)
throws
InterruptedException {
        
List<String> a =
new
ArrayList<String>();
        
a.add(
"a"
);
        
a.add(
"b"
);
        
a.add(
"c"
);
        
final
CopyOnWriteArrayList<String> list =
new
CopyOnWriteArrayList<String>(a);
        
Thread t =
new
Thread(
new
Runnable() {
            
int
count = -
1
;
 
            
@Override
            
public
void
run() {
                
while
(
true
) {
                    
list.add(count++ +
""
);
                
}
            
}
        
});
        
t.setDaemon(
true
);
        
t.start();
        
Thread.currentThread().sleep(
3
);
        
for
(String s : list) {
            
System.out.println(list.hashCode());
            
System.out.println(s);
        
}
    
}
}

这段代码在for循环中遍历list的时候,同时会输出list的hashcode来看看list是不是同一个list了。

部分输出结果如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
669661746
a
2119153548
b
471684173
c
550648901
-
1
-
76447331
0
1638154873
1
921225916
2
1618672031
3
1404182932
4
950140076
5
-
610377050
6
-
610377050
7
-
610377050
8
-
610377050
9
-
610377050
10
-
610377050
11
-
610377050
12

从上面的结果很容易就看出来,hashcode变化了多次,说明了list已经不是原来的list对象了。这说明了CopyOnWriteArrayList类的add函数在执行的时候确实是修改了list的数组对象。

看add函数的代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
/**
     
* Appends the specified element to the end of this list.
     
*
     
* @param e element to be appended to this list
     
* @return <tt>true</tt> (as specified by {@link Collection#add})
     
*/
    
public
boolean
add(E e) {
    
final
ReentrantLock lock =
this
.lock;
    
lock.lock();
    
try
{
        
Object[] elements = getArray();
        
int
len = elements.length;
        
Object[] newElements = Arrays.copyOf(elements, len +
1
);
        
newElements[len] = e;
        
setArray(newElements);
        
return
true
;
    
}
finally
{
        
lock.unlock();
    
}
    
}

add函数中拷贝了原来的数组并在最后加上了新元素。然后调用setArray函数将引用链接到新数组:

1
2
3
4
5
6
/**
    
* Sets the array.
    
*/
   
final
void
setArray(Object[] a) {
       
array = a;
   
}

转载于:https://www.cnblogs.com/Cher-blogs/p/8041944.html

你可能感兴趣的文章
转 lucene3搜索引擎,索引建立搜索排序分页高亮显示, IKAnalyzer分词
查看>>
ASP.net在线购物商城系统完全解析
查看>>
bootstrap datetimepicker 位置错误
查看>>
9结构型模式之代理模式
查看>>
第二节 整型数据
查看>>
Python 序列
查看>>
Liferay的架构:缓存(第一部分)
查看>>
初识B/S结构编程技术
查看>>
方法、hadoop源码之JobQueueTaskScheduler-by小雨
查看>>
页面重构总结
查看>>
IO 函数
查看>>
Unity V3 初步使用 —— 为我的.NET项目从简单三层架构转到IOC做准备
查看>>
JSP页面间传递参数
查看>>
VSNETcodePrint 2005 & SQL ServerPrint 2005
查看>>
java数组基本操作
查看>>
String的indexOf()用于获取字符串中某个子字符串的位置
查看>>
shell 脚本运算符
查看>>
杭电 1711 Number Sequence
查看>>
又一道软通动力7K月薪面试题——银行业务调度系统
查看>>
Matlab画图-非常具体,非常全面
查看>>