Java~常見的倆個鎖物件改變的問題 (字串物件的改變和物件屬性的改變)

2020-10-05 11:01:09

  • 注意一個問題如果多個執行緒同時持有鎖物件, 且同時持有的是相同的鎖物件, 那麼這些執行緒之間的任務就是同步的, 如果分別持有不同的鎖物件, 那麼就是非同步的.

字串物件的改變

  • 任務程式碼
/**
 * Created with IntelliJ IDEA.
 * Description: If you don't work hard, you will a loser.
 * User: Listen-Y.
 * Date: 2020-10-03
 * Time: 21:17
 */
public class MyService {

    private  String lock = "123";

    public void testMethod() {

        synchronized (lock) {
            System.out.println(Thread.currentThread().getName() + " begin at: "
                    + System.currentTimeMillis());
            lock = "456";

            try {
                Thread.sleep(2000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName() + " end at: "
                    + System.currentTimeMillis());

        }

    }
}

  • 執行緒類和啟動類
/**
 * Created with IntelliJ IDEA.
 * Description: If you don't work hard, you will a loser.
 * User: Listen-Y.
 * Date: 2020-10-03
 * Time: 21:21
 */
public class Run2 {


    public static void main(String[] args) throws InterruptedException {
        MyService service = new MyService();
        Thread t1 = new Thread("A") {
            @Override
            public void run() {
                service.testMethod();
            }
        };
        Thread t2 = new Thread("B") {
            @Override
            public void run() {
                service.testMethod();
            }
        };
        t1.start();
        //關鍵點 這裡等待0.1秒, A執行緒等待2秒
        Thread.sleep(100);
        t2.start();
    }
}

  • 執行結果
    在這裡插入圖片描述
  • 此時我們發現A和B倆個執行緒是A獲得鎖進入之後過了100秒後B也獲得鎖進入了, 但是此時A並沒有出去, 也就是A並沒有釋放鎖, 究其原因就是A進入之後再0.1秒內修改了lock這個物件, 要知道字串型別"123"和"456"是倆個不同的型別, 所以才會有這樣的現象, 如果我們不讓等待那0.1秒, 就不會出現這樣的問題
    在這裡插入圖片描述
  • 註釋掉後就不會有這樣的問題
    在這裡插入圖片描述
  • 此時A和B差不多是同時要求啟動, 倆個執行緒之間一開始競爭的還是"123"這把鎖, 雖然將鎖改成"456" , 但結果還是非同步的, 因為共同爭搶的鎖是"123"

物件屬性的改變

  • user類
public class User {

    public String name;
    public int age;

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

}
  • 服務類
public class Service {

    public void testMethod(User user) {
        synchronized (user) {
            System.out.println(Thread.currentThread().getName() + " begin: " +
                    System.currentTimeMillis());
            //修改資訊
            user.age = 99;
            user.name = "HaHa";
            try {
                Thread.sleep(3000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            System.out.println(Thread.currentThread().getName() + " end: " +
                    System.currentTimeMillis());
        }
    }

}
  • 啟動類
/**
 * Created with IntelliJ IDEA.
 * Description: If you don't work hard, you will a loser.
 * User: Listen-Y.
 * Date: 2020-10-03
 * Time: 21:50
 */
public class Run3 {

    public static void main(String[] args) throws InterruptedException {
        User user = new User("listen", 20);
        Service service = new Service();

        Thread t1 = new Thread("A") {
            @Override
            public void run() {
                service.testMethod(user);
            }
        };
        Thread t2 = new Thread("B") {
            @Override
            public void run() {
                service.testMethod(user);
            }
        };
        t1.start();
        //關鍵點
        Thread.sleep(100);
        t2.start();
    }
}

  • 執行結果
    在這裡插入圖片描述
  • 這個程式碼我們發現, 只要物件不變, 即使屬性被改變, 執行的結果還是同步的