线程安全类-线程同步

当一个类很好的同步并保护它的数据时,那么这个类就可以说是“线程安全的”
在类的层面上来说是线程安全的,但是操作多个线程仍然不是安全的。
比如说一个集合是线程安全的,两个线程操作同一个集合对象,第一个线程查询集合非空后,删除集合当中的第一个元素。第二个线程也执行与第一个线程相同的操作,第一个线程查询非空后,第二个线程查询也非空。第二个线程再执行删除,显然是不对的,因此此时集合已经没有元素了。
举个例子:

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

上述结果是正确的,无论你运行多少次,都不会出现“数组下标越界”的错误,因为线程和线程是同步执行的。

猜你喜欢

转载自blog.csdn.net/qq_24630433/article/details/88399130