2025-02-15

可惡的Java多線程,一直沒搞懂同步的作用!

一直以為同步的時候隻要鎖住對象就能順序執行瞭:

[java]
public class Test { 
    final static byte[] b = new byte[0]; 
 
    public static void main(String[] args) { 
        Test t = new Test(); 
        t.thread.start(); 
        Test t2 = new Test(); 
        t2.thread.start(); 
    } 
 
    Thread thread = new Thread(new Runnable() { 
        @Override 
        public void run() { 
            test(); 
        } 
    }); 
 
    public void test() { 
        synchronized (this) { 
            for (int n = 0; n < 100; n++) { 
                System.out.println(thread.getName() + ":" + n); 
            try { 
                Thread.sleep(1000); 
            } catch (InterruptedException e) { 
                e.printStackTrace(); 
            } 
            } 
        } 
    } 

public class Test {
    final static byte[] b = new byte[0];

    public static void main(String[] args) {
        Test t = new Test();
        t.thread.start();
        Test t2 = new Test();
        t2.thread.start();
    }

    Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            test();
        }
    });

    public void test() {
        synchronized (this) {
            for (int n = 0; n < 100; n++) {
                System.out.println(thread.getName() + ":" + n);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            }
        }
    }
}
但是這樣是錯誤的!兩個線程還是交替執行!

 

查閱瞭很多資料才知道上面這個鎖是不正確的,兩個線程鎖住的this對象不是同一個,所以導致交叉執行。應該修改為:

[java]
public class Test { 
    final static byte[] b = new byte[0]; 
 
    public static void main(String[] args) { 
        Test t = new Test(); 
        t.thread.start(); 
        t.test(); 
    } 
 
    Thread thread = new Thread(new Runnable() { 
        @Override 
        public void run() { 
            test(); 
        } 
    }); 
 
    public void test() { 
        synchronized (this) { 
            for (int n = 0; n < 100; n++) { 
                System.out.println(thread.getName() + ":" + n); 
            try { 
                Thread.sleep(1000); 
            } catch (InterruptedException e) { 
                e.printStackTrace(); 
            } 
            } 
        } 
 
    } 

public class Test {
    final static byte[] b = new byte[0];

    public static void main(String[] args) {
        Test t = new Test();
        t.thread.start();
        t.test();
    }

    Thread thread = new Thread(new Runnable() {
        @Override
        public void run() {
            test();
        }
    });

    public void test() {
        synchronized (this) {
            for (int n = 0; n < 100; n++) {
                System.out.println(thread.getName() + ":" + n);
            try {
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            }
        }

    }
}
這樣的確就是順序執行瞭,因為函數鎖住的this對象是同一個,如果去除線程同步當然就會交叉執行啦。

但是我還有點不明白的是第一個例子錯誤的原因是其鎖住的對象不是同一個,但是如果我把this改為一個全局靜態常量還是不正確!理論上全局靜態常量整個運行周期內存中隻會有一個對象阿!不明白為什麼還是不行!希望有高手可以解答。

 

其實我們用到同步多半是為瞭讓線程順序執行,比如在做Android開發的時候,我們通常希望前臺顯示一個進度框,後臺線程去執行下載動作,下載完之後前臺線程在執行餘下操作如界面顯示。

這個時候其實可以使用線程的join()!

oin方法大傢可以查下api,它的意思是等待當前線程執行完後執行完畢才執行其他線程。也就是說如果一個類中有這樣一個代碼段:

      thread1.start();

      thread2.start();

      thread1.join();

      thread2.join();

     do something 1;

     do something 2;

那麼這段代碼會等待兩個線程執行完畢後再執行 do something 1 和 do something 2,註意:必須先啟動所有線程,再join。如果啟動一個就join一個,結果是什麼?對,那就會是等待thread1執行完再執行thread2,再執行後續代碼。

 

作者:h3c4lenovo

發佈留言

發佈留言必須填寫的電子郵件地址不會公開。 必填欄位標示為 *