并发场景下list的空指针异常和size大小问题
Posted 啥也不会,啥也没有!
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了并发场景下list的空指针异常和size大小问题相关的知识,希望对你有一定的参考价值。
并发场景下list的空指针异常和size大小问题
问题描述:
对一个源list使用并行流对其进行遍历的时候往宿list添加元素,再次遍历宿list的时候会抛出空指针异常问题而且会现宿list size大小也有问题。
问题复原:
@org.junit.Test
public void test2() {
List<Integer> source = new LinkedList<>();
List<String> target = new LinkedList<>();
for (int i = 0; i < 1000; i++) {
source.add(i);
}
source.parallelStream().forEach(i -> {
target.add(String.valueOf(i));
});
System.out.println("target size -> " + target.size());
for (String s : target) {
System.out.println(s);
}
}
运行结果
问题分析:
不开启多线程的时候targetList的size一定是1000的,而且不会出现空指针异常。
这两个问题其实都和size++这句话有关
1. size大小为什么不是1000
分析源码:
add是尾插,源码如下
void linkLast(E e) {
final Node<E> l = last;
final Node<E> newNode = new Node<>(l, e, null);
last = newNode;
if (l == null)
first = newNode;
else
l.next = newNode;
size++;
modCount++;
}
模拟一个场景
- size现在的值为100
- 线程a拿到了size大小100,此时cpu让出执行权给线程b
- 线程b拿到了size大小也为100
- 那么无论他们谁先加1,最后size的值会被101覆盖两次,导致size的大小不会是102
2. 再次遍历target的时候为什么会报空指针异常问题
其实也和尾插法这段代码有关
模拟场景:
-
设现在的size为100
-
线程a拿到了链表尾部元素last 之后让出执行权给线程b
-
线程b也拿到了相同的last之后一直执行完了add操作,此时size = 101
-
线程a也执行了 l.next = newNode;覆盖了线程b的在size = 101 位置上的值,之后也进行了size++的操作,size = 102
-
此时出现的问题就是size = 101 位置上的值被覆盖了两次,但是102位置上的值是null。
-
所以遍历的时候会报空指针异常。
-
因为last = newNode;这一步的重复覆盖,可以预测所有的null都会是链表末尾。
3. 关于为什么foreach增强for循环为什么会报空指针的问题
Linkedlist的foreach循环,是依赖Iterator的,LinkedList也有自己的迭代器,源码如下
可以看出hasnext的判断并不是node.next != null 而是 nextIndex < size 所以即使null都在末尾也会在 next = next.next的时候报空指针异常。
3. 问题解决
List<String> target = Collections.synchronizedList(new LinkedList<>());
让需要进行add操作的list,转换成线程安全的。
关于ArrayList
其实也是和size++有关,与LinkedList不同的是由于实现尾插的方式不一致,所以导致null可能在中间
源码如下:
结果如下:
标度适应性测试的空指针异常
[创建一个scaleFitnessTest算法来测试binarry值的适合度并使用权重(质数),然后将它们在标尺的'左侧'和'右侧'之间移动
实际规模适应性的逻辑有效,但是在测试null参数时,我得到了nullpointer异常
我试图满足的要求是:
该方法在以下情况下应返回-100:
1]如果“ rep”或“ weights”的大小为零,或者二者之一为零空。
2)如果“ rep”的大小大于权数的数量。
我的代码如下
public static double ScalesFitness(ArrayList<Boolean> rep, ArrayList<Double> weights)
if( (rep.size() == 0 || weights.size() == 0) || (rep == null || weights == null) )
return (-100);
if (rep.size() > weights.size())
return(-100);
double lhs = 0.0,rhs = 0.0;
int n = rep.size();
for(int i=0;i<n;i++)
if (rep.get(i) == true)
lhs = lhs + weights.get(i);
else
rhs = rhs + weights.get(i);
return(Math.abs(lhs-rhs));
size()
之前先检查是否为空以上是关于并发场景下list的空指针异常和size大小问题的主要内容,如果未能解决你的问题,请参考以下文章
记录一些遇见的bug——记录一个使用多线程异步调用openfeign时子线程丢失request请求头导致的空指针异常错误