今天导师在群里问下面这段代码,list也改了线程安全的List,循环一万次往list里塞元素,为什么看size都是小于一万的,而且每次的值都是不一样的?
仔细看了代码,确实也感觉奇怪。明明已经用了线程安全的list,应该不存在线程冲突的问题啊。但看这不确定的结果,又是线程不安全的表现。
最后,组内的大佬说,可能是list.size()的问题,list.size()查看大小的时候也是阻塞的,可能别的线程还在插入,list.size()查看的时候把list阻塞了。可以试试sleep一段时间后再list.size(),看还会不会出现这种现象。
试了下,果然不再出现了。强啊
补个chatGPT的解释:
线程安全list 的size()会导致阻塞吗
在某些情况下,线程安全的list的size()可能会导致阻塞。这取决于具体的实现方式
对于某些实现,size()是非常快速的,可以立即返回list的大小,而不会阻塞任何线程。这通常是通过维护一个计数器或计算list的大小来实现的。因此,如果您使用这样的实现,调用size()方法不会阻塞
然而,对于另一些实现,size()可能需要遍历整个list,以便计算大小。在这种情况下,当调用size()方法时,如果其他线程正在修改list,可能会发生阻塞。因为在遍历list时,会获取个锁来保证遍历的原子性,如果其他线程正在修改list,则size()方法需要等待该锁被释放才能继续执行,这可能导致阻塞
因此,具体取决于使用的线程安全list的实现方式。建议使用实现了“快速失败”机制的list,即在多线程环境下,如果list在遍历时被修改,会立即抛出ConcurrentModificationException异常,以避免因为阻塞导致的性能问题。
代码:
package main.java.threadpool ;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;import java.util.Random;
public class ThreadTest {
public static void main(String[] args) throws Exception {
long start = System.currentTimeMillis();
List<Integer> list = Collections.synchronizedList(new ArrayList<>());
for (int i = 0; i < 100000; i++) {
Thread t = new Thread() {
@Override
public void run() {
list.add(new Random().nextInt());
}
};
t.start();
System.out.println("time:" + (System.currentTimeMillis() - start));
System.out.println("size:" + list.size());
}
}
}