哪个是线程安全的
public class ListHelper<E>{
public List<E> list = Collections.synchronizedList(new ArrayList<E>());
...
public synchronized boolean putIfAbsent(E x){
boolean absent = !list.contains(x);
if(absent){
list.add(x);
return absent;
}
}
}
---------------------------------------------------------------------------------------------
public class ListHelper<E>{
public List<E> list = Collections.synchronizedList(new ArrayList<E>());
...
public boolean putIfAbsent(E x){
synchronized(list){
boolean absent = !list.contains(x);
if(absent){
list.add(x);
return absent;
}
}
}
}
这两个代码,不同的地方是synchronized一个是修饰了方法,一个是修饰了list,目的都是让list线程安全,书上写的上面的写法不是线程安全的,下面的是线程安全的,线程安全的解释我可以理解,但上面的写法为什么不是线程安全的?
------解决方案-------------------- up up up up up up up
------解决方案-------------------- up up up up up
------解决方案-------------------- synchronized修饰方法是获得本对象的锁,而不是list
在boolean absent = !list.contains(x);和list.add(x);之间,list就有可能会被别的对象改变(比如通过反射),导致线程不安全
用synchronized(list)的话就不会了
------解决方案-------------------- 从操作角度来看,用了Collections.synchronizedList,不会出现数据错误,
数组越界 之类
从逻辑绝度来看,下面的也不见得安全,用list做锁,其他没synchronized(list)的代码块可以直接操作list
而contains 和 add两个动作中间有间隙,其他操作非synchronized(list)可以从中间插入
假设类中其他代码块操作list的时候都有synchronized(list),可以认为是安全的
但同样道理,类中其他操作list的方法全部用synchronized修饰其实也很安全
------解决方案-------------------- Collections操作集合的对象,源代码中也是将对象(要进行加锁)的对象都设置为final的,一般都这样.一般不会把普通的对象进行lock,要么就用类字节码对象lock.
------解决方案-------------------- 我给你解释下吧。
首先的你的List已经是线程安全的了(public List<E> list = Collections.synchronizedList(new ArrayList<E>());具体可参见API),但是你写了个方法实现无重复添加的功能,上面的方法,对方法加synchronized,假如已经执行到 if 行了,别的地方调用了add,这时boolean absent = !list.contains(x)的判断已经无效了,就出现你说的list不安全了。第二种给List加synchronized就OK,因为你在进入时,别的地方不能调用add
------解决方案-------------------- 第一个获得ListHelper 对象的锁,这把锁和list对象明显是不同的锁。进入同步块后到退出前,其它的线程还能调用list.add(),list.remove()方法。
但第二个例子,因为 synchronized(list),这时操作的是list对象的锁,也就是list.add(),list.contains()等方法用的是同一把锁,当进入同步块时,其它的线程不可能在同步块退出前调用list.add(),list.remove()等这些同步方法,所以是线程安全的。
------解决方案-------------------- 两种都没有绝对的线程安全。
------解决方案-------------------- 引用: 从操作角度来看,用了Collections.synchronizedList,不会出现数据错误,数组越界之类
从逻辑绝度来看,下面的也不见得安全,用list做锁,其他没synchronized(list)的代码块可以直接操作list
而contains 和 add两个动作中间有间隙,其他操作非synchronized(list)可以从中间插入
假设类中其他代码块操作list的时候都有synchronized(list),可以认为是安全的
但同样道理,类中其他操作list的方法全部用synchronized修饰其实也很安全
看了下源码,发觉自己错了。
SynchronizedList的锁就是自己本身,所以第二中的确是能锁住的