JUC總結(jié)

JUC總結(jié)

線程與進(jìn)程

進(jìn)程:是程序運(yùn)行和資源分配的基本單位,一個(gè)程序至少有一個(gè)進(jìn)程唉擂,一個(gè)進(jìn)程至少有一個(gè)線程想帅。進(jìn)程在執(zhí)行過(guò)程中擁有獨(dú)立的內(nèi)存單元,而多個(gè)線程共享內(nèi)存資源尿庐,減少切換次數(shù)忠怖,從而效率更高。

線程:是進(jìn)程的一個(gè)實(shí)體抄瑟,是 cpu 調(diào)度和分派的基本單位凡泣,是比程序更小的能獨(dú)立運(yùn)行的基本單位。同一進(jìn)程中的多個(gè)線程之間可以并發(fā)執(zhí)行锐借。

java如何開(kāi)啟線程问麸?

通過(guò)底層調(diào)用C語(yǔ)言,所以java本身無(wú)法創(chuàng)建線程钞翔!

public synchronized void start() {
        /**
         * This method is not invoked for the main method thread or "system"
         * group threads created/set up by the VM. Any new functionality added
         * to this method in the future may have to also be added to the VM.
         *
         * A zero status value corresponds to state "NEW".
         */
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
        /* Notify the group that this thread is about to be started
         * so that it can be added to the group's list of threads
         * and the group's unstarted count can be decremented. */
        group.add(this);
        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
    /* do nothing. If start0 threw a Throwable then
    it will be passed up the call stack */
            }
        }
    }

    // 本地方法严卖,底層的C++ ,Java 無(wú)法直接操作硬件 
    private native void start0();

并發(fā)與并行

并發(fā)(多線程操作同一個(gè)資源)

  • CPU一核 布轿,模擬出來(lái)多條線程哮笆,天下武功,唯快不破汰扭,快速交替

并行(多個(gè)人一起行走)

  • CPU多核 稠肘,多個(gè)線程可以同時(shí)執(zhí)行; 線程池

并行是在不同實(shí)體上的多個(gè)事件,并發(fā)是在同一實(shí)體上的多個(gè)事件

線程的幾種狀態(tài)

public enum State {
    // 新生
    NEW,
    // 運(yùn)行 
    RUNNABLE,
    // 阻塞 
    BLOCKED,
    // 等待萝毛,死死地等 
    WAITING,
    // 超時(shí)等待 
    TIMED_WAITING,
    // 終止
    TERMINATED;
}

wait/sleep 區(qū)別

  1. sleep() 方法正在執(zhí)行的線程主動(dòng)讓出 cpu(然后 cpu 就可以去執(zhí)行其他任務(wù))项阴,在 sleep 指定時(shí)間后 cpu 再回到該線程繼續(xù)往下執(zhí)行(注意:sleep 方法只讓出了 cpu,而并不會(huì)釋放同步資源鎖)笆包;

    而 wait() 方法則是指當(dāng)前線程讓自己暫時(shí)退讓出同步資源鎖环揽,以便其他正在等待該資源的線程得到該資源進(jìn)而運(yùn)行略荡,只有調(diào)用了 notify() 方法,之前調(diào)用 wait() 的線程才會(huì)解除 wait 狀態(tài)歉胶,可以去參與競(jìng)爭(zhēng)同步資源鎖汛兜,進(jìn)而得到執(zhí)行。(注意:notify 的作用相當(dāng)于叫醒睡著的人通今,而并不會(huì)給他分配任務(wù)粥谬,就是說(shuō) notify 只是讓之前調(diào)用 wait 的線程有權(quán)利重新參與線程的調(diào)度);

  2. sleep() 方法可以在任何地方使用辫塌,而 wait() 方法則只能在同步方法或同步塊中使用漏策;

  3. sleep() 是線程類(Thread)的方法,調(diào)用會(huì)暫停此線程指定的時(shí)間璃氢,但監(jiān)控依然保持哟玷,不會(huì)釋放對(duì)象鎖,到時(shí)間自動(dòng)恢復(fù)一也;wait() 是 Object 的方法巢寡,調(diào)用會(huì)放棄對(duì)象鎖,進(jìn)入等待隊(duì)列椰苟,待調(diào)用 notify()/notifyAll() 喚醒指定的線程或者所有線程抑月,才會(huì)進(jìn)入鎖池,不再次獲得對(duì)象鎖才會(huì)進(jìn)入運(yùn)行狀態(tài)舆蝴。

    wait 會(huì)釋放鎖谦絮,sleep 睡覺(jué)了,抱著鎖睡覺(jué)洁仗,不會(huì)釋放!

Lock鎖

傳統(tǒng)Synchronized

  1. 修飾實(shí)例方法:作用于當(dāng)前對(duì)象實(shí)例加鎖层皱,進(jìn)入同步代碼前要獲得當(dāng)前對(duì)象實(shí)例的鎖;

  2. 修飾靜態(tài)方法:作用于當(dāng)前類對(duì)象加鎖赠潦,進(jìn)入同步代碼前要獲得當(dāng)前類對(duì)象的鎖 叫胖。也就是給當(dāng)前類加鎖,會(huì)作用于類的所有對(duì)象實(shí)例她奥,因?yàn)殪o態(tài)成員不屬于任何一個(gè)實(shí)例對(duì)象瓮增,是類成員(static 表明這是該類的一個(gè)靜態(tài)資源,不管 new了多少個(gè)對(duì)象哩俭,只有一份绷跑,所以對(duì)該類的所有對(duì)象都加了鎖)。

    所以如果一個(gè)線程 A 調(diào)用一個(gè)實(shí)例對(duì)象的非靜態(tài) synchronized 方法凡资,而線程 B 需要調(diào)用這個(gè)實(shí)例對(duì)象所屬類的靜態(tài) synchronized 方法砸捏,是允許的,不會(huì)發(fā)生互斥現(xiàn)象,因?yàn)樵L問(wèn)靜態(tài) synchronized 方法占用的鎖是當(dāng)前類的鎖带膜,而訪問(wèn)非靜態(tài) synchronized 方法占用的鎖是當(dāng)前實(shí)例對(duì)象鎖吩谦;

  3. 修飾代碼塊:指定加鎖對(duì)象鸳谜,對(duì)給定對(duì)象加鎖膝藕,進(jìn)入同步代碼庫(kù)前要獲得給定對(duì)象的鎖。和 synchronized 方法一樣咐扭,synchronized(this) 代碼塊也是鎖定當(dāng)前對(duì)象的芭挽。synchronized 關(guān)鍵字加到 static 靜態(tài)方法和 synchronized(class) 代碼塊上都是是給 Class 類上鎖。這里再提一下:synchronized 關(guān)鍵字加到非 static 靜態(tài)方法上是給對(duì)象實(shí)例上鎖蝗肪。另外需要注意的是:盡量不要使用 synchronized(String a) 因?yàn)?JVM 中袜爪,字符串常量池具有緩沖功能。

Lock接口

實(shí)現(xiàn)類:

  • ReentrantLock(可重入鎖 常用)
  • ReentrantReadWriteLock.ReadLock(讀鎖)
  • ReentrantReadWriteLock.WriteLock(寫(xiě)鎖)
public ReentrantLock() {
        sync = new NonfairSync(); //非公平鎖
}

    
public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();//公平鎖
}

公平鎖:十分公平:可以先來(lái)后到

非公平鎖:十分不公平:可以插隊(duì) (默認(rèn))

Synchronized 和 Lock 區(qū)別

  1. Synchronized是內(nèi)置的Java關(guān)鍵字薛闪, Lock 是一個(gè)接口

  2. Synchronized無(wú)法判斷獲取鎖的狀態(tài)辛馆,Lock 可以判斷是否獲取到了鎖

  3. Synchronized會(huì)自動(dòng)釋放鎖,lock 必須要手動(dòng)釋放鎖!如果不釋放鎖豁延,死鎖

  4. Synchronized 線程 1(獲得鎖昙篙,阻塞)、線程2(等待诱咏,傻傻的等);Lock鎖就不一定會(huì)等待下去;

  5. Synchronized 可重入鎖苔可,不可以中斷的,非公平;Lock 可重入鎖袋狞,可以判斷鎖焚辅,非公平(可以自己設(shè)置);

生產(chǎn)者和消費(fèi)者問(wèn)題

Synchronized實(shí)現(xiàn)

class Data1 {
    private int number = 0;

    public synchronized void increment() throws InterruptedException {
        while (number != 0) {
            this.wait();
        }
        number++;
        System.out.println(Thread.currentThread().getName() + ":" + number);
        this.notifyAll();
    }

    public synchronized void decrement() throws InterruptedException {
        while (number != 1) {
            this.wait();
        }
        number--;
        System.out.println(Thread.currentThread().getName() + ":" + number);
        this.notifyAll();
    }
}

lock實(shí)現(xiàn)

Sychronized---->lock(Lock)

wait---->await(Condition)

notifiy---->signal(Condition)

class Data2 {
    private int number = 0;
    Lock lock = new ReentrantLock();
    Condition condition = lock.newCondition();

    public void increment() throws InterruptedException {
        lock.lock();
        try {
            while (number != 0) {
                condition.await();
            }
            number++;
            System.out.println(Thread.currentThread().getName() + ":" + number);
            condition.signalAll();
        } finally {
            lock.unlock();
        }

    }

    public  void decrement() throws InterruptedException {
        lock.lock();
        try {
            while (number != 1) {
                condition.await();
            }
            number--;
            System.out.println(Thread.currentThread().getName() + ":" + number);
            condition.signalAll();
        } finally {
            lock.unlock();
        }
    }
}

測(cè)試類

public class Test {
    public static void main(String[] args) {
        Data data = new Data();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "A").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.increment();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "B").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "C").start();
        new Thread(() -> {
            for (int i = 0; i < 10; i++) {
                try {
                    data.decrement();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }, "D").start();
    }
}

注意(虛假喚醒)

當(dāng)一個(gè)條件滿足時(shí),很多線程都被喚醒了苟鸯,但是只有其中部分是有用的喚醒同蜻,其它的喚醒都是無(wú)用功。比如說(shuō)買(mǎi)貨早处,如果商品本來(lái)沒(méi)有貨物湾蔓,突然進(jìn)了一件商品,這是所有的線程都被喚醒了 陕赃,但是只能一個(gè)人買(mǎi)卵蛉,所以其他人都是假喚醒,獲取不到對(duì)象的鎖么库。

如何解決傻丝?必須將if改成while

Condition實(shí)現(xiàn)精準(zhǔn)通知和喚醒線程

目的:使喚醒順序?yàn)锳BC有序

class Data3{
    int number =1; //1A 2B 3C
    Lock lock=new ReentrantLock();
    Condition condition1=lock.newCondition();
    Condition condition2=lock.newCondition();
    Condition condition3=lock.newCondition();
    public void printA(){
        lock.lock();
        try {
            while (number !=1){//2,3
                condition1.await();
            }
            System.out.println(Thread.currentThread().getName()+"=>AAAAAAA");
            number=2;
            condition2.signal();

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }
    public void printB(){
        lock.lock();
        try {
            while (number !=2){//1,3
                condition2.await();
            }
            System.out.println(Thread.currentThread().getName()+"=>BBBBBBB");
            number=3;
            condition3.signal();

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }
    public void printC(){
        lock.lock();
        try {
            while (number !=3){ //1,2
                condition3.await();
            }
            System.out.println(Thread.currentThread().getName()+"=>CCCCCCC");
            number=1;
            condition1.signal();

        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }

    }
}

測(cè)試

 public static void main(String[] args) {
        Data3 data3 = new Data3();
        new Thread(()->{
            for (int i = 0; i < 10; i++) {
                data3.printA();
            }
        },"A").start();
        new Thread(()->{for (int i = 0; i < 10; i++) {
            data3.printB();
        }},"B").start();
        new Thread(()->{for (int i = 0; i < 10; i++) {
            data3.printC();
        }},"C").start();
    }
    
結(jié)果:
A=>AAAAAAA
B=>BBBBBBB
C=>CCCCCCC
A=>AAAAAAA
B=>BBBBBBB
C=>CCCCCCC
...
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市诉儒,隨后出現(xiàn)的幾起案子萧豆,更是在濱河造成了極大的恐慌,老刑警劉巖捞附,帶你破解...
    沈念sama閱讀 210,978評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異滤愕,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)怜校,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,954評(píng)論 2 384
  • 文/潘曉璐 我一進(jìn)店門(mén)间影,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人茄茁,你說(shuō)我怎么就攤上這事魂贬。” “怎么了裙顽?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,623評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵付燥,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我愈犹,道長(zhǎng)键科,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,324評(píng)論 1 282
  • 正文 為了忘掉前任漩怎,我火速辦了婚禮勋颖,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘扬卷。我一直安慰自己牙言,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,390評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布怪得。 她就那樣靜靜地躺著咱枉,像睡著了一般。 火紅的嫁衣襯著肌膚如雪徒恋。 梳的紋絲不亂的頭發(fā)上蚕断,一...
    開(kāi)封第一講書(shū)人閱讀 49,741評(píng)論 1 289
  • 那天,我揣著相機(jī)與錄音入挣,去河邊找鬼亿乳。 笑死,一個(gè)胖子當(dāng)著我的面吹牛径筏,可吹牛的內(nèi)容都是我干的葛假。 我是一名探鬼主播,決...
    沈念sama閱讀 38,892評(píng)論 3 405
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼滋恬,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼聊训!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起恢氯,我...
    開(kāi)封第一講書(shū)人閱讀 37,655評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤带斑,失蹤者是張志新(化名)和其女友劉穎鼓寺,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體勋磕,經(jīng)...
    沈念sama閱讀 44,104評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡妈候,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,451評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了挂滓。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片苦银。...
    茶點(diǎn)故事閱讀 38,569評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖杂彭,靈堂內(nèi)的尸體忽然破棺而出墓毒,到底是詐尸還是另有隱情,我是刑警寧澤亲怠,帶...
    沈念sama閱讀 34,254評(píng)論 4 328
  • 正文 年R本政府宣布,位于F島的核電站柠辞,受9級(jí)特大地震影響团秽,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜叭首,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,834評(píng)論 3 312
  • 文/蒙蒙 一习勤、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧焙格,春花似錦图毕、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,725評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至冬阳,卻和暖如春蛤虐,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背肝陪。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,950評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工驳庭, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人氯窍。 一個(gè)月前我還...
    沈念sama閱讀 46,260評(píng)論 2 360
  • 正文 我出身青樓饲常,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親狼讨。 傳聞我的和親對(duì)象是個(gè)殘疾皇子贝淤,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,446評(píng)論 2 348

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