1. 程式人生 > 實用技巧 >java測試執行緒不安全簡單Demo

java測試執行緒不安全簡單Demo

描述場景

初學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塊來加鎖.
以上只是個人的見解,可能還有很多漏洞.請指教.