描述场景
初学java的时候,对线程安全和不安全一直都是一个模糊的状态,接下来的这段日志我会继续深入了解多线程,以及线程安全的相关知识,
下面我用一个简单的小案例来测试一下多线程场景下导致的不安全问题.
>设计场景:
一个学校统计这个学校有多少个学生,我们每创建一个学生,学生就加1,这样我们就用这个计数来统计学校最后有多少学生.
- 学生实体类
public class Student {
private String name;
private String code;
private int age;
public static int count = 0;
public Student(){
count++;
}
public Student(String name) {
this.name = name;
count++;
}
public Student(int age) {
this.age = age;
count++;
}
public Student(String name, String code, int age) {
this.name = name;
this.code = code;
this.age = age;
count++;
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", code='" + code + '\'' +
", age=" + age +
'}';
}
}
-线程用来表示每个班级创建多少个学生
public class StudentThread extends Thread {
@Override
public void run() {
//每个班级创建20个人,循环一次创建两个人
for (int i = 0; i < 10; i++) {
Student s = new Student();
System.out.print(Student.count+" ");
Student s1 = new Student(i);
System.out.print(Student.count+" ");
}
}
}
-测试类
public class TestThread {
public static void main(String[] args) {
//假设有两个班级,那就是要创建1个线程
for (int i = 0; i < 1; i++) {
new StudentThread().start();
}
}
}
-测试结果
结果分析:从结果上来,返回的数字是我们预期想要的结果是从1-20个这么计数没错,但这个是在1个线程使用的时候.相当于此时就一个班级在统计人,
所以是不可能统计错的,那么现在又加了一个班级,结果又是怎么样的呢?
-测试类
public class TestThread {
public static void main(String[] args) {
//假设有两个班级,那就是要创建1个线程
for (int i = 0; i < 2; i++) {
new StudentThread().start();
}
}
}
-测试结果
结果分析:从结果可以看到,有重复的数字,说明两个线程同时的时候,会存在不清楚数据目前的状态,就会有重复的数据,
导致线程不安全.以此类推,2个线程都出现这种情况,那么增加到10个线程,那么错误率会更高.
那么我们要怎么处理,才能使线程变得安全?解决方案就是给线程加锁,在别人使用的时候,其他人不能去修改它,只能等别人使用完后才能进去操作这个线程.
-改进方法
public class StudentThread extends Thread {
@Override
public void run() {
//这是一把钥匙,只有拿到这把钥匙才能进synchronized(相当于门锁)这个方法
Boolean Flag = true;
synchronized (Flag) {
for (int i = 0; i < 10; i++) {
Student s = new Student();
System.out.print(Student.count+" ");
Student s1 = new Student(i);
System.out.print(Student.count+" ");
}
}
}
}
-测试结果
结果分析:不过运行多少次,增加多少个线程,都不会有重复的数据,也不会乱序,因为每一个线程进来都要拿一把钥匙,这个线程进去后,其他线程在外等候,
等这个线程处理完归还钥匙,其他线程拿到钥匙才能进去.
总结
在多线程的情况下会出现线程安全问题,需要我们加锁,来保证线程的安全,单线程的情况下不会有线程安全的问题.大家还可以使用synchronized的方法来进行修改,我用的是synchronized块来加锁.
以上只是个人的见解,可能还有很多漏洞.请指教.