多線程系列04-Syncronized關(guān)鍵字

Java中床估,每個對象有且只有一個同步鎖。調(diào)用對象的synchronized方法時,就獲取了該對象的同步鎖蛋欣。
Java中一共有兩種類型的鎖
Java類鎖(全局鎖):類鎖是用synchronized修飾類的靜態(tài)方法或者一個類的class對象(一個類只有一個.class對象)
Java對象鎖(實例鎖):對象鎖用synchronize修飾普通方法或者代碼塊
不同線程對鎖的訪問是互斥的。

synchronized的基本規(guī)則:
規(guī)則一. 當一個線程訪問“某對象”的“synchronized方法”或者“synchronized代碼塊”時如贷,其他線程對“該對象”的該“synchronized方法”或者“synchronized代碼塊”的訪問將被阻塞陷虎。
示例:

public class MyRunnable implements Runnable{
    @Override
    public void run() {
        //獲取當前對象的同步鎖
        synchronized (this){
            try{
                for(int i =0; i<5; i++){
                    Thread.sleep(100);
                    System.out.println(Thread.currentThread().getName() + " loop " + i);
                }
            }catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }

    public static void main(String[] args) {
        Runnable demo = new MyRunnable();

        Thread thread1 = new Thread(demo,"thread1");
        Thread thread2 = new Thread(demo,"thread2");
        thread2.start();
        thread1.start();
    }
}

運行結(jié)果:

thread2 loop 0
thread2 loop 1
thread2 loop 2
thread2 loop 3
thread2 loop 4
thread1 loop 0
thread1 loop 1
thread1 loop 2
thread1 loop 3
thread1 loop 4

結(jié)果說明:
thread1和thread2都是基于"demo這個Runnable對象"創(chuàng)建的線程。這就意味著杠袱,我們可以將synchronized(this)中的this看作是“demo這個Runnable對象”尚猿;因此,線程t1和t2共享“demo對象的同步鎖”楣富。

另一個例子:

public class MyThread extends Thread {

    public MyThread(String name){
        super(name);
    }

    @Override
    public void run() {
        //獲取當前對象的同步鎖
        synchronized (this){
            for(int i =0; i<5; i++){
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println(Thread.currentThread().getName() + " loop " + i);
            }
        }
    }

    public static void main(String[] args) {
        Thread thread1 = new MyThread("thread1");
        Thread thread2 = new MyThread("thread2");
        thread2.start();
        thread1.start();
    }
}

運行結(jié)果:

thread2 loop 0
thread1 loop 0
thread1 loop 1
thread2 loop 1
thread1 loop 2
thread2 loop 2
thread2 loop 3
thread1 loop 3
thread2 loop 4
thread1 loop 4

結(jié)果說明:
synchronized(this)中的this代表的是MyThread對象凿掂,而t1和t2是兩個不同的MyThread對象,因此t1和t2在執(zhí)行synchronized(this)時纹蝴,獲取的是不同對象的同步鎖庄萎。

規(guī)則二. 當一個線程訪問“某對象”的“synchronized方法”或者“synchronized代碼塊”時踪少,其他線程仍然可以訪問“該對象”的非同步代碼塊。

public class Count {

    public void synMethod(){
        synchronized(this) {
            try {
                for (int i = 0; i < 5; i++) {
                    Thread.sleep(100); // 休眠100ms
                    System.out.println(Thread.currentThread().getName() + " synMethod loop " + i);
                }
            } catch (InterruptedException ie) {
            }
        }
    }

    public void nonSynMethod(){
        try {
            for (int i = 0; i < 5; i++) {
                Thread.sleep(100); // 休眠100ms
                System.out.println(Thread.currentThread().getName() + " nonSynMethod loop " + i);
            }
        } catch (InterruptedException ie) {
        }
    }

    public static void main(String[] args) {
        final Count count = new Count();

        Thread t1 = new Thread(new Runnable() {
            public void run() {
                count.synMethod();
            }
        }, "t1");

        Thread t2 = new Thread(new Runnable() {
            public void run() {
                count.nonSynMethod();
                                count.synMethod();
            }
        }, "t2");

        t1.start();
        t2.start();
    }
}

運行結(jié)果:

t2 nonSynMethod loop 0
t1 synMethod loop 0
t1 synMethod loop 1
t2 nonSynMethod loop 1
t2 nonSynMethod loop 2
t1 synMethod loop 2
t2 nonSynMethod loop 3
t1 synMethod loop 3
t2 nonSynMethod loop 4
t1 synMethod loop 4
t2 synMethod loop 0
t2 synMethod loop 1
t2 synMethod loop 2
t2 synMethod loop 3
t2 synMethod loop 4

結(jié)果說明:t1糠涛,t2均訪問的count對象秉馏,t1先獲取到count對象的實例鎖,t2先訪問count的非同步代碼塊脱羡。等t1釋放鎖后萝究,t2訪問count對象的同步代碼塊。

規(guī)則三. 當一個線程訪問“某對象”的“synchronized方法”或者“synchronized代碼塊”時锉罐,其他線程對“該對象”的其他的“synchronized方法”或者“synchronized代碼塊”的訪問將被阻塞帆竹。
示例:

public class Count {

    //含有synchronized同步塊的方法
    public void synMethod1(){
        synchronized (this){
            try {
                for (int i = 0; i < 5; i++) {
                    Thread.sleep(110); // 休眠110ms
                    System.out.println(Thread.currentThread().getName() + " synMethod1 loop " + i);
                    }
                } catch (InterruptedException ie) {
            }
        }
    }

    //含有synchronized同步塊的方法
    public void synMethod2(){
        synchronized (this){
            try {
                for (int i = 0; i < 6; i++) {
                    Thread.sleep(110); // 休眠110ms
                    System.out.println(Thread.currentThread().getName() + " synMethod2 loop " + i);
                }
            } catch (InterruptedException ie) {
            }
        }
    }

    //非同步的方法
    public void nonsynMethod(){
        try {
            for (int i = 0; i < 6; i++) {
                Thread.sleep(100); // 休眠100ms
                System.out.println(Thread.currentThread().getName() + " nonsynMethod loop " + i);
            }
        } catch (InterruptedException ie) {
        }
    }

    public static void main(String[] args) {
        final Count count = new Count();

        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                count.synMethod1();
            }
        },"thread1");

        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                count.nonsynMethod();
            }
        },"thread2");

        Thread thread3 = new Thread(new Runnable() {
            @Override
            public void run() {
                count.synMethod2();
            }
        },"thread3");

        thread1.start();
        thread2.start();
        thread3.start();

    }
}

運行結(jié)果:

thread2 nonsynMethod loop 0
thread1 synMethod1 loop 0
thread2 nonsynMethod loop 1
thread1 synMethod1 loop 1
thread2 nonsynMethod loop 2
thread1 synMethod1 loop 2
thread2 nonsynMethod loop 3
thread1 synMethod1 loop 3
thread1 nonsynMethod loop 4
thread1 synMethod1 loop 4
thread2 nonsynMethod loop 5
thread3 synMethod2 loop 0
thread1 synMethod2 loop 1
thread3 synMethod2 loop 2
thread3 synMethod2 loop 3
thread3 synMethod2 loop 4
thread3 synMethod2 loop 5

結(jié)果說明:
thread1,thread1脓规,thread3都是基于同一個count對象創(chuàng)建的線程栽连。

關(guān)于全局鎖和實例鎖的一些說明:

pulbic class Something {
    public synchronized void isSyncA(){}
    public synchronized void isSyncB(){}
    public static synchronized void cSyncA(){}
    public static synchronized void cSyncB(){}
}

(01) x.isSyncA()與x.isSyncB()
(02) x.isSyncA()與y.isSyncA()
(03) x.cSyncA()與y.cSyncB()
(04) x.isSyncA()與Something.cSyncA()

(01) 不能被同時訪問。因為isSyncA()和isSyncB()都是訪問同一個對象(對象x)的同步鎖侨舆!

public class LockDemo {

    public synchronized void isSyncA() {
        try {
            for (int i=0;i<5;i++) {
                Thread.sleep(100);
                System.out.println(Thread.currentThread().getName() + " : isSyncA");
            }
        } catch (InterruptedException ie) {
        }
    }

    public synchronized void isSyncB(){
        try {
            for (int i=0;i<5;i++) {
                Thread.sleep(100);
                System.out.println(Thread.currentThread().getName() + " : isSyncB");
            }
        } catch (InterruptedException ie) {
        }
    }

    public static void main(String[] args) {

        final LockDemo lockDemo1 = new LockDemo();
        final LockDemo lockDemo2 = new LockDemo();

        Thread t11 = new Thread(new Runnable() {
            @Override
            public void run() {
                lockDemo1.isSyncA();
            }
        },"t11");

        Thread t12 = new Thread(new Runnable() {
            @Override
            public void run() {
                lockDemo1.isSyncB();
            }
        },"t12");

        t11.start();
        t12.start();
    }
}

運行結(jié)果:

t11 : isSyncA
t11 : isSyncA
t11 : isSyncA
t11 : isSyncA
t11 : isSyncA
t12 : isSyncB
t12 : isSyncB
t12 : isSyncB
t12 : isSyncB
t12 : isSyncB

結(jié)果說明:訪問的均是lockDemo1對象的同步鎖秒紧。

(02) 可以同時被訪問

public class LockDemo {

    public synchronized void isSyncA() {
        try {
            for (int i=0;i<5;i++) {
                Thread.sleep(100);
                System.out.println(Thread.currentThread().getName() + " : isSyncA");
            }
        } catch (InterruptedException ie) {
        }
    }

    public synchronized void isSyncB(){
        try {
            for (int i=0;i<5;i++) {
                Thread.sleep(100);
                System.out.println(Thread.currentThread().getName() + " : isSyncB");
            }
        } catch (InterruptedException ie) {
        }
    }

    public static void main(String[] args) {

        final LockDemo lockDemo1 = new LockDemo();
        final LockDemo lockDemo2 = new LockDemo();

        Thread t11 = new Thread(new Runnable() {
            @Override
            public void run() {
                lockDemo1.isSyncA();
            }
        },"t11");

        Thread t12 = new Thread(new Runnable() {
            @Override
            public void run() {
                lockDemo2.isSyncB();
            }
        },"t12");

        t11.start();
        t12.start();
    }
}

運行結(jié)果:

t12 : isSyncB
t11 : isSyncA
t12 : isSyncB
t11 : isSyncA
t12 : isSyncB
t11 : isSyncA
t12 : isSyncB
t11 : isSyncA
t12 : isSyncB
t11 : isSyncA

結(jié)果說明:訪問的是lockDemo1與lockDemo2兩個對象的同步鎖。

(03) 不能被同時訪問挨下。

public class LockDemo {

    public synchronized void isSyncA() {
        try {
            for (int i=0;i<5;i++) {
                Thread.sleep(100);
                System.out.println(Thread.currentThread().getName() + " : isSyncA");
            }
        } catch (InterruptedException ie) {
        }
    }

    public synchronized void isSyncB(){
        try {
            for (int i=0;i<5;i++) {
                Thread.sleep(100);
                System.out.println(Thread.currentThread().getName() + " : isSyncB");
            }
        } catch (InterruptedException ie) {
        }
    }

    public static synchronized void cSyncA(){
        try{
            for (int i=0;i<5;i++) {
                Thread.sleep(100);
                System.out.println(Thread.currentThread().getName() + " : csyncA");
            }
        } catch (InterruptedException ie) {
        }
    }

    public static synchronized void cSyncB(){
        try{
            for (int i=0;i<5;i++) {
                Thread.sleep(100);
                System.out.println(Thread.currentThread().getName() + " : csyncB");
            }
        } catch (InterruptedException ie) {
        }
    }

    public static void main(String[] args) {

        final LockDemo lockDemo1 = new LockDemo();
        final LockDemo lockDemo2 = new LockDemo();

        Thread t11 = new Thread(new Runnable() {
            @Override
            public void run() {
                lockDemo1.isSyncA();
            }
        },"t11");

        Thread t12 = new Thread(new Runnable() {
            @Override
            public void run() {
                lockDemo2.isSyncB();
            }
        },"t12");

        Thread t13 = new Thread(new Runnable() {
            @Override
            public void run() {
                LockDemo.cSyncA();
            }
        },"t13");

        Thread t14 = new Thread(new Runnable() {
            @Override
            public void run() {
                LockDemo.cSyncB();
            }
        },"t14");

//        t11.start();
//        t12.start();
        t13.start();
        t14.start();
    }
}

運行結(jié)果:

t13 : csyncA
t13 : csyncA
t13 : csyncA
t13 : csyncA
t13 : csyncA
t14 : csyncB
t14 : csyncB
t14 : csyncB
t14 : csyncB
t14 : csyncB

結(jié)果說明:訪問的都是LockDemo的同步鎖

(04) 可以被同時訪問熔恢。
運行結(jié)果:

t13 : csyncA
t12 : isSyncB
t12 : isSyncB
t13 : csyncA
t13 : csyncA
t12 : isSyncB
t13 : csyncA
t12 : isSyncB
t13 : csyncA
t12 : isSyncB

結(jié)果說明:因為isSyncA()是實例方法,x.isSyncA()使用的是對象x的鎖臭笆;而cSyncA()是靜態(tài)方法叙淌,Something.cSyncA()可以理解對使用的是“類的鎖”。因此愁铺,它們是可以被同時訪問的鹰霍。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市茵乱,隨后出現(xiàn)的幾起案子茂洒,更是在濱河造成了極大的恐慌,老刑警劉巖瓶竭,帶你破解...
    沈念sama閱讀 221,198評論 6 514
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件督勺,死亡現(xiàn)場離奇詭異,居然都是意外死亡在验,警方通過查閱死者的電腦和手機玷氏,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,334評論 3 398
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來腋舌,“玉大人,你說我怎么就攤上這事渗蟹】榻龋” “怎么了赞辩?”我有些...
    開封第一講書人閱讀 167,643評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長授艰。 經(jīng)常有香客問我辨嗽,道長,這世上最難降的妖魔是什么淮腾? 我笑而不...
    開封第一講書人閱讀 59,495評論 1 296
  • 正文 為了忘掉前任糟需,我火速辦了婚禮,結(jié)果婚禮上谷朝,老公的妹妹穿的比我還像新娘洲押。我一直安慰自己,他們只是感情好圆凰,可當我...
    茶點故事閱讀 68,502評論 6 397
  • 文/花漫 我一把揭開白布杈帐。 她就那樣靜靜地躺著,像睡著了一般专钉。 火紅的嫁衣襯著肌膚如雪挑童。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,156評論 1 308
  • 那天跃须,我揣著相機與錄音站叼,去河邊找鬼。 笑死菇民,一個胖子當著我的面吹牛大年,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播玉雾,決...
    沈念sama閱讀 40,743評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼翔试,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了复旬?” 一聲冷哼從身側(cè)響起垦缅,我...
    開封第一講書人閱讀 39,659評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎驹碍,沒想到半個月后壁涎,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,200評論 1 319
  • 正文 獨居荒郊野嶺守林人離奇死亡志秃,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 38,282評論 3 340
  • 正文 我和宋清朗相戀三年怔球,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片浮还。...
    茶點故事閱讀 40,424評論 1 352
  • 序言:一個原本活蹦亂跳的男人離奇死亡竟坛,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情担汤,我是刑警寧澤涎跨,帶...
    沈念sama閱讀 36,107評論 5 349
  • 正文 年R本政府宣布,位于F島的核電站崭歧,受9級特大地震影響隅很,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜率碾,卻給世界環(huán)境...
    茶點故事閱讀 41,789評論 3 333
  • 文/蒙蒙 一叔营、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧所宰,春花似錦绒尊、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,264評論 0 23
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至件炉,卻和暖如春勘究,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背斟冕。 一陣腳步聲響...
    開封第一講書人閱讀 33,390評論 1 271
  • 我被黑心中介騙來泰國打工口糕, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人磕蛇。 一個月前我還...
    沈念sama閱讀 48,798評論 3 376
  • 正文 我出身青樓景描,卻偏偏與公主長得像,于是被迫代替她去往敵國和親秀撇。 傳聞我的和親對象是個殘疾皇子超棺,可洞房花燭夜當晚...
    茶點故事閱讀 45,435評論 2 359

推薦閱讀更多精彩內(nèi)容