当一个类很好的同步并保护它的数据时,那么这个类就可以说是“线程安全的”
在类的层面上来说是线程安全的,但是操作多个线程仍然不是安全的。
比如说一个集合是线程安全的,两个线程操作同一个集合对象,第一个线程查询集合非空后,删除集合当中的第一个元素。第二个线程也执行与第一个线程相同的操作,第一个线程查询非空后,第二个线程查询也非空。第二个线程再执行删除,显然是不对的,因此此时集合已经没有元素了。
举个例子:
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
public class Thread_Safe {
}
class NameList{
private List<String> nameList= Collections.synchronizedList(new LinkedList<>());
public void add(String name){
nameList.add(name);
}
public String removeFirst() {
if (nameList.size() > 0) {
return (String)nameList.remove(0);
} else{
return null;
}
}
public static void main(String[] args){
final NameList nameList=new NameList();
nameList.add("张三");
class InsideThreadExtend extends Thread{
@Override
public void run() {
String name=nameList.removeFirst();
System.out.println("删除的名字为:"+name);
}
}
Thread thread1=new InsideThreadExtend();
Thread thread2=new InsideThreadExtend();
Thread thread3=new InsideThreadExtend();
Thread thread4=new InsideThreadExtend();
Thread thread5=new InsideThreadExtend();
Thread thread6=new InsideThreadExtend();
Thread thread7=new InsideThreadExtend();
Thread thread8=new InsideThreadExtend();
Thread thread9=new InsideThreadExtend();
Thread thread10=new InsideThreadExtend();
thread1.start();
thread2.start();
thread3.start();
thread4.start();
thread5.start();
thread6.start();
thread7.start();
thread8.start();
thread9.start();
thread10.start();
}
}
结果为:
Exception in thread "Thread-1" 删除的名字为:张三
删除的名字为:null
删除的名字为:null
删除的名字为:null
删除的名字为:null
删除的名字为:null
删除的名字为:null
删除的名字为:null
删除的名字为:null
java.lang.IndexOutOfBoundsException: Index: 0, Size: 0
at java.util.LinkedList.checkElementIndex(LinkedList.java:555)
at java.util.LinkedList.remove(LinkedList.java:525)
at java.util.Collections$SynchronizedList.remove(Collections.java:2426)
at NameList.removeFirst(Thread_Safe.java:15)
at NameList$1InsideThreadExtend.run(Thread_Safe.java:28)
Process finished with exit code 0
通过结果可以看出,已经报错了,原因是上一个线程的操作无法阻止第二个线程的操作。上述错误并不是一定会发生,多运行几次,可能就会出现这种错误,解决这个问题的办法就是使用synchronized关键字。
代码如下:
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
public class Thread_Safe {
}
class NameList{
private List<String> nameList= Collections.synchronizedList(new LinkedList<>());
public synchronized void add(String name){
nameList.add(name);
}
public synchronized String removeFirst() {
if (nameList.size() > 0) {
return (String)nameList.remove(0);
} else{
return null;
}
}
public static void main(String[] args){
final NameList nameList=new NameList();
nameList.add("张三");
class InsideThreadExtend extends Thread{
@Override
public void run() {
String name=nameList.removeFirst();
System.out.println("删除的名字为:"+name);
}
}
Thread thread1=new InsideThreadExtend();
Thread thread2=new InsideThreadExtend();
Thread thread3=new InsideThreadExtend();
Thread thread4=new InsideThreadExtend();
Thread thread5=new InsideThreadExtend();
Thread thread6=new InsideThreadExtend();
Thread thread7=new InsideThreadExtend();
Thread thread8=new InsideThreadExtend();
Thread thread9=new InsideThreadExtend();
Thread thread10=new InsideThreadExtend();
thread1.start();
thread2.start();
thread3.start();
thread4.start();
thread5.start();
thread6.start();
thread7.start();
thread8.start();
thread9.start();
thread10.start();
}
}
结果如下:
删除的名字为:张三
删除的名字为:null
删除的名字为:null
删除的名字为:null
删除的名字为:null
删除的名字为:null
删除的名字为:null
删除的名字为:null
删除的名字为:null
删除的名字为:null
上述结果是正确的,无论你运行多少次,都不会出现“数组下标越界”的错误,因为线程和线程是同步执行的。