当一个类已经很好的同步以保护它的数据时,这个类就称为“线程安全的”。
即使是线程安全类,也应该特别小心,因为操作的线程之间仍然不一定安全。
举个形象的例子,比如一个集合是线程安全的,有两个线程在操作同一个集合对象,当第一个线程查询集合非空后,删除集合中所有元素的时候。第二个线程也来执行与第一个线程相同的操作,也许在第一个线程查询后,第二个线程也查询出集合非空,但是当第一个执行清除后,第二个再执行删除显然是不对的,因为此时集合已经为空了。
举个例子:
public class NameList {
private List nameList = Collections.synchronizedList(newLinkedList());
public void add(String name) {
nameList.add(name);
}
public String removeFirst() {
if (nameList.size()>0) {
return (String) nameList.remove(0);
} else {
return null;
}
}
}
public class TestNameList {
public static void main(String[] args) {
final NameList nl =new NameList();
nl.add("苏东坡");
class NameDropper extends Thread{
@Override
public void run() {
String name = nl.removeFirst();
System.out.println(name);
}
}
Thread t1=new NameDropper();
Thread t2=new NameDropper();
t1.start();
t2.start();
}
}
执行结果:
苏东坡
null
虽然集合对象
private List nameList =Collections.synchronizedList(new LinkedList());
是同步的,但是程序还不是线程安全的。
出现这种事件的原因是,上例中一个线程操作列表过程中无法阻止另外一个线程对列表的其他操作。
解决上面问题的办法是,在操作集合对象的NameList上面做一个同步。改写后的代码如下:
public class NameList {
private List nameList = Collections.synchronizedList(newLinkedList());
public synchronized void add(String name) {
nameList.add(name);
}
public synchronized StringremoveFirst() {
if (nameList.size()>0) {
return (String) nameList.remove(0);
} else {
return null;
}
}
}
这样,当一个线程访问其中一个同步方法时,其他线程只有等待。
网友评论