synchronized鎖的用法

synchronized關鍵字能夠分爲對象鎖和類鎖兩個大類。java

1.對象鎖

將synchronized關鍵字加載非static方法上:ide

public class testss {
    public synchronized void minus(){
        int count = 5;
        while (count >= 0){
            System.out.println(Thread.currentThread().getName() + "    " + count);
            count--;
        }
    }   
}

測試類:測試

public class Main {
    public static void main(String[] args) {
        testss t = new testss();
        new Thread(new Runnable() {
            @Override
            public void run() {
                t.minus();
            }
        }).start();
            new Thread(new Runnable() {
            @Override
            public void run() {
                t.minus();
            }
        }).start();
    }
}

運行結果:
由於調用的方法有synchronized關鍵字的存在,兩個線程啓動事後按順序運行,順序不會隨機發生錯亂,可是兩個線程哪個首先開始執行並不必定。線程

Thread-0    5
Thread-0    4
Thread-0    3
Thread-0    2
Thread-0    1
Thread-0    0
Thread-1    5
Thread-1    4
Thread-1    3
Thread-1    2
Thread-1    1
Thread-1    0

咱們修改一下,測試一下當一個線程訪問synchronized方法的時候,另外一個線程可否訪問其餘的synchronized方法,咱們添加一個內容同樣的synchronized方法minus2(),觀察執行結果:code

public class testss {
    public synchronized void minus(){
        int count = 5;
        while (count >= 0){
            System.out.println(Thread.currentThread().getName() + "    " + count);
        count--;
        }
    }
    public synchronized void minus2(){
        int count = 5;
        while (count >= 0){
            System.out.println(Thread.currentThread().getName() + "    " + count);
            count--;
        }
    }
}

測試類:對象

public class Main {
    public static void main(String[] args) {
        testss t = new testss();
        new Thread(new Runnable() {
            @Override
            public void run() {
                t.minus();
            }
        }).start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                t.minus2();
            }
        }).start();
    }
}

測試結果:進程

Thread-0    5
Thread-0    4
Thread-0    3
Thread-0    2
Thread-0    1
Thread-0    0
Thread-1    5
Thread-1    4
Thread-1    3
Thread-1    2
Thread-1    1
Thread-1    0

會發如今一個線程訪問一個對象的synchronized方法的時候,另外一個線程也不能訪問同一個對象的synchronized方法。,這時候若是去掉minus2()的synchronized關鍵字,讓它變成一個非同步的方法,那麼執行的結果又是亂序的。get

如今有一個問題就是爲何稱添加在非static方法前面的synchronized關鍵字爲對象鎖?咱們看一下代碼:同步

class Mytest {
    public synchronized void minus(){
        int count = 5;
        while (count > 0){
            System.out.println(Thread.currentThread().getName() + "  1  " + count);
            count--;
        };
    }
}

public class Main {
    public static void main(String[] args) throws InterruptedException {
        final Mytest test = new Mytest();
        final Mytest test2 = new Mytest();
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                test.minus();
            }
        });
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                test2.minus2();
            }
        });
        thread1.start();
        thread2.start();
    }
}

這時,咱們設置的是兩個不一樣的實例化對象分別調用類中的同步方法,執行的結果是:io

Thread-0  1  5
Thread-1  2  5
Thread-0  1  4
Thread-1  2  4
Thread-0  1  3
Thread-1  2  3
Thread-1  2  2
Thread-1  2  1
Thread-0  1  2
Thread-0  1  1

亂序的。
也就說明了添加在普通方法前面的synchronized關鍵字,只能保證在同一個對象中這個方法是同步的,在不一樣的對象調用這個方法的時候synchronized是沒法影響執行的。這也就是爲何叫對象鎖。

2.類鎖

類鎖的用法是修飾類中的static方法,或者使用代碼塊,需引用當前的類。

public static synchronized void test(){
    // TODO
}


public static void test(){
    synchronized (TestSynchronized.class) {
        // TODO
    }
}

首先類鎖在多個進程同時訪問該同步方法的時候效果與對象鎖是一致的:

class Mytest {
    public static synchronized void minus(){
        int count = 5;
        while (count > 0){
            System.out.println(Thread.currentThread().getName() + "  1  " + count);
            count--;
        };
    }
}

public class Main {
    public static void main(String[] args) throws InterruptedException {
        final Mytest test = new Mytest();
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                test.minus();
            }
        });
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                test.minus();
            }
        });
        thread1.start();
        thread2.start();
    }
}
Thread-0  1  5
Thread-0  1  4
Thread-0  1  3
Thread-0  1  2
Thread-0  1  1
Thread-1  1  5
Thread-1  1  4
Thread-1  1  3
Thread-1  1  2
Thread-1  1  1

可是當類中有一個類鎖,有一個對象鎖的時候,效果如何:

class Mytest {
    public static synchronized void minus(){
        int count = 5;
        while (count > 0){
            System.out.println(Thread.currentThread().getName() + "  1  " + count);
            count--;
        };
    }
    public synchronized void minus2(){
        int count = 5;
        while (count > 0){
            System.out.println(Thread.currentThread().getName() + "  2  " + count);
            count--;
        };
    }
}

public class Main {
    public static void main(String[] args) throws InterruptedException {
        final Mytest test = new Mytest();
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                test.minus();
            }
        });
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                test.minus2();
            }
        });
        thread1.start();
        thread2.start();
    }
}

結果以下:

Thread-0  1  5
Thread-0  1  4
Thread-1  2  5
Thread-0  1  3
Thread-0  1  2
Thread-0  1  1
Thread-1  2  4
Thread-1  2  3
Thread-1  2  2
Thread-1  2  1

所以能夠發現對象鎖和類鎖是互不影響的。

再看看若是使用兩個實例對象來調用同一個同步了的靜態方法是否會收類鎖的影響:

class Mytest {
    public static synchronized void minus(){
        int count = 5;
        while (count > 0){
            System.out.println(Thread.currentThread().getName() + "  1  " + count);
            count--;
        };
    }
}

public class Main {
    public static void main(String[] args) throws InterruptedException {
        final Mytest test = new Mytest();
        final Mytest test2 = new Mytest();
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                test.minus();
            }
        });
        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                test2.minus();
            }
        });
        thread1.start();
        thread2.start();
    }
}

結果:

Thread-0  1  5
Thread-0  1  4
Thread-0  1  3
Thread-0  1  2
Thread-0  1  1
Thread-1  1  5
Thread-1  1  4
Thread-1  1  3
Thread-1  1  2
Thread-1  1  1

因此類鎖是能覆蓋到全部實例化這個類的對象的,所以就算使用不一樣的對象調用類中的同步的static方法,仍是會受到類鎖的影響。

3.總結

synchronized關鍵字用在普通方法上只對當前的對象的這個方法有同步做用。且當一個線程執行同步方法時,其餘線程不可訪問該對象的其餘同步方法,可是能夠訪問不一樣步的方法。synchronized關鍵字用在static方法上對任何實例化這個類的對象均有效。可是不影響對象鎖方法的執行。

相關文章
相關標籤/搜索