多線程(4) — 同步互斥與通信

多線程問題:比如銀行轉(zhuǎn)賬等問題

synchronized:"同步 = 加鎖 ":含有synchronized關(guān)鍵字的代碼塊,同時最多只能有一個線程運行并鎖定,當有其它線程運行時要先檢查有沒有其它線程在使用,若有則等待其線程運行完后再運行,若沒有則直接運行并上鎖。相當于不受CPU切換的干擾。

多線程對同一資源進行處理時,CPU會隨機快速切換,所以會出現(xiàn)線程A的方法處理一半,線程B接收調(diào)用B的方法,導(dǎo)致線程不安全,如下:

public class SynchronizedTest {

    public static void main(String[] args) {
        final Phone phone = new Phone();
        new Thread(new Runnable() {    // 1. Thread1
            @Override
            public void run() {
                while (true){
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    phone.getPhone("iphone-x plus");
                }
            }
        }).start();

        new Thread(){      // 2. Thread2
            @Override
            public void run() {
                while (true){
                    try {
                        Thread.sleep(10);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    phone.getPhone("小米特別版");
                }
            }
        }.start();
    }

}

// 調(diào)用的公共方法
class Phone {
    public void getPhone(String phone){
        for (int i=0; i<phone.length();i++){
            System.out.print(phone.charAt(i));
        }
        System.out.println("---------");
    }
}

====console===
iphone-x plus---------
小米特別版---------
iphone-x plus---------
小米特別版---------
iphone-x p小米特別版---------
lus---------

所以會出現(xiàn)數(shù)據(jù)錯誤的情況。

解決:
如果只需要同步一部分代碼塊可以用 synchronized(this){ ... } 來完成,這里有個小問題就是this,synchronized 需要指定的是同一個對象,如果兩個線程中的對象名稱不一樣那么在synchronized()括號里就不知道寫什么,而且容易出現(xiàn)指的不是同一對象的情況,這樣不起作用,所以在這里用this就是指向調(diào)用該方法的對象。如下就會報錯 :

class Phone {
    public void getPhone(String phone){
        synchronized (phone){            //1 . phone 沒有效果 
            for (int i=0; i<phone.length();i++){
                System.out.print(phone.charAt(i));
            }
            System.out.println("---------");
        }
    }
}

===console====
iphone-x plus---------
小米特iphone-x plus---------
別版---------
iphone-x plus---------
小米特別版

代碼中1的phone指是“iphone-x plus”與“小米特別版”也就是當?shù)谝粋€方法進來的時候是為第一個iphone-x的加鎖,當小米進來的時候又是小米所以不是同一個對象無法控制鎖,就好比一間確實上鎖的房子,但訪問者進入了另一間房子。

而且同一個方法最好只加一個synchronized,否則會出現(xiàn)互不相讓而死鎖的情況。

接下來討論三種方法間是否線程互斥,(第二個線程調(diào)用getPhone2()方法)

class Phone {

    //1. 
    public void getPhone(String phone){
        synchronized (this){
            for (int i=0; i<phone.length();i++){
                System.out.print(phone.charAt(i));
            }
            System.out.println("---------");
        }

    }

    //2.
    public synchronized void getPhone2(String phone){
            for (int i=0; i<phone.length();i++){
                System.out.print(phone.charAt(i));
            }
            System.out.println("---------");
    }

    //3.
    public static synchronized void getPhone3(String phone){
        for (int i=0; i<phone.length();i++){
            System.out.print(phone.charAt(i));
        }
        System.out.println("---------");
    }

}

在console上顯示的結(jié)果是12同步、13不同步、23不同步。
12同步:第二個方法其實默認的this與第1個方法是一樣的對象,所以線程是互斥的同步。
13與23不同步:static靜態(tài)方法運行時要有鎖對象與之關(guān)聯(lián),似乎找不到鎖對象,類的字節(jié)碼在內(nèi)存里面也算是對象,靜態(tài)方法運行的時候不用創(chuàng)建類的實例對象,因為靜態(tài)方法在jvm類加載時就已經(jīng)加載并分配內(nèi)存了。而此時字節(jié)碼對象已經(jīng)在內(nèi)存里面了,所以要實現(xiàn)比如13同步就可以用字節(jié)碼對象來保證同步。
(而獲取類的字節(jié)碼在起手式—Object中的getClass()中提到,可以用.class來獲取。)

image.png

果然,在改成類的字節(jié)碼之后13的數(shù)據(jù)就正常了,13互斥。
(class Phone 放在外面就相當于Phone.class如果拉到SynchronizedTest內(nèi)部就變成SynchronizedTest.Phone.class所以再建文件時候不會沖突)
(這里又對static靜態(tài)方法、反射、jvm類加載其它知識進行了擴充)

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • Java多線程學習 [-] 一擴展javalangThread類 二實現(xiàn)javalangRunnable接口 三T...
    影馳閱讀 3,107評論 1 18
  • 該文章轉(zhuǎn)自:http://blog.csdn.net/evankaka/article/details/44153...
    加來依藍閱讀 7,469評論 3 87
  • 本文主要講了java中多線程的使用方法、線程同步、線程數(shù)據(jù)傳遞、線程狀態(tài)及相應(yīng)的一些線程函數(shù)用法、概述等。 首先講...
    李欣陽閱讀 2,597評論 1 15
  • 生于北方,對于南北的認知就是北方是簡單而堅決的黑白,黑山白水。南方則是艷麗鮮妍,朱門黛瓦。所以自小便對字里行間的艷...
    阡陌舒篁閱讀 265評論 0 0
  • 在辦公室待了一天,晚上出來去廣場散散步,順便散散心。外面雖然有點冷,但所幸近幾天有風,空氣還算清新,星星和月亮清晰...
    暗相隨閱讀 873評論 0 1

友情鏈接更多精彩內(nèi)容