2 回答
TA贡献1796条经验 获得超7个赞
首先要明白,synchronize加锁的一般都是对某个对象而言的(也可以对类进行加锁)。
1中非线程安全的synchronized的加锁对象其实是ListHelper<E>实例化的对象,而不是list,其他的线程无法再对该ListHelper<E>实例化的对象进行操作,对于该例,就是无法再进行putIfAbsent()方法的使用,但是其中的list是public的,所以可以直接对list进行操作,比如list.add()等操作,进而造成线程不安全
TA贡献1864条经验 获得超6个赞
大概是由于public List<E> list = Collections.synchronizedList(new ArrayList<E>());
的这个list是public的,可以被直接修改的。
假如有多个线程直接修改这个list。
方法1虽然把putIfAbsent(E x)
这个方法加锁了,但是其他线程依然可以修改由于public暴露出来的list。
比如线程A:listHelper.list.add(x)
的时候,线程B刚好在执行boolean absent = !list.contains(x);
,有可能线程A把x添加进去了,但是线程B的absent也判断为true,然后线程B就再次add了x。
方法2是根据list加锁,所以只有持有list的锁才能进入判断和添加,当线程A在listHelper.list.add(x)
的时候,线程B是不能进入到synchronized (list)
方法内的
添加回答
举报