11.并行流-多线程的安全问题-加同步锁/使用线程安全的容器/toArray方法或者collect
针对线程安全问题,我们可以采取的解决方案有哪些呢?
- 加同步锁
- 使用线程安全的容器
- toArray方法或者collect
加同步锁
在多线程的处理下,肯定会出现数据安全问题,如下:
多线程安全问题复现
@Test
@DisplayName("并行流-多线程的数据安全问题")
public void test31() {
ArrayList<Integer> list = new ArrayList<>();
for (int i = 0; i < 1000 ; i++) {
list.add(i);
}
System.out.println(list.size());
List<Integer> newList = new ArrayList<>();
list.parallelStream().forEach(newList::add);
System.out.println(newList.size());
}
Result:
1000
964
java.lang.Exception: No tests found matching Method test31(com.lzh.ShizhanStreamTests) from org.junit.vintage.engine.descriptor.RunnerRequest@11758f2a
at org.junit.internal.requests.FilterRequest.getRunner(FilterRequest.java:40)
针对这个问题,我们的解决方法如下:【加同步锁】
@org.junit.Test
@DisplayName("解决并行流-多线程的数据安全问题")
public void test32() {
ArrayList<Integer> list = new ArrayList<>();
for (int i = 0; i < 1000 ; i++) {
list.add(i);
}
System.out.println(list.size());
List<Integer> newList = new ArrayList<>();
Object obj = new Object();
list.parallelStream().forEach(s-> {
synchronized(obj){
newList.add(s);
}
});
System.out.println(newList.size());
}
1000
1000
线程安全问题:
@org.junit.Test
@DisplayName("并行流2-多线程的数据安全问题")
public void test33() {
List<Integer> newList = new ArrayList<Integer>();
IntStream.rangeClosed(0,1000).parallel().forEach(i -> newList.add(i));
}
消耗时间4
java.lang.ArrayIndexOutOfBoundsException: 15
【加同步锁】
@org.junit.Test
@DisplayName("解决并行流2-多线程的数据安全问题")
public void test33() {
Object obj = new Object();
List<Integer> newList = new ArrayList<Integer>();
IntStream.rangeClosed(0,1000).parallel().forEach(i -> {
synchronized (obj){
newList.add(i);
}
});
System.out.println(newList.size());
}
1001
使用线程安全的容器
Vector 是一个线程安全的容器
@org.junit.Test
@DisplayName("使用线程安全的容器")
public void test34() {
Vector v = new Vector();
Object obj = new Object();
IntStream.rangeClosed(0,1000).parallel().forEach(i -> {
synchronized (obj){
v.add(i);
}
});
System.out.println(v.size());
}
不过网上说,不建议使用Vector
其他解决线程安全问题的解决方案
我们还可以通过Stream中的toArray方法或者collect方法,这两个方法就是满足线程安全的。
@org.junit.Test
@DisplayName("toArray方法解决线程安全")
public void test35() {
List<Integer> newList = new ArrayList<Integer>();
List<Integer> collect = IntStream.rangeClosed(0, 1000).parallel()
.boxed()
.collect(Collectors.toList());
System.out.println("collect = " + collect);
System.out.println(collect.size());
}
collect = [0, 1, 2, 3,...1001]
1001