欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java 深入淺出分析Synchronized原理與Callable接口

 更新時(shí)間:2022年03月23日 16:03:30   作者:/少司命  
Synchronized關(guān)鍵字解決的是多個(gè)線程之間訪問資源的同步性,synchronized關(guān)鍵字可以保證被它修飾的方法或者代碼塊在任意時(shí)刻只能有一個(gè)線程執(zhí)行,Runnable是執(zhí)行工作的獨(dú)立任務(wù),但是不返回任何值。如果我們希望任務(wù)完成之后有返回值,可以實(shí)現(xiàn)Callable接口

一、基本特點(diǎn)

1. 開始時(shí)是樂觀鎖, 如果鎖沖突頻繁, 就轉(zhuǎn)換為悲觀鎖.

2. 開始是輕量級(jí)鎖實(shí)現(xiàn), 如果鎖被持有的時(shí)間較長, 就轉(zhuǎn)換成重量級(jí)鎖.

3. 實(shí)現(xiàn)輕量級(jí)鎖的時(shí)候大概率用到的自旋鎖策略

4. 是一種不公平鎖

5. 是一種可重入鎖

6. 不是讀寫鎖

二、加鎖工作過程

JVM 將 synchronized 鎖分為 無鎖、偏向鎖、輕量級(jí)鎖、重量級(jí)鎖狀態(tài)。會(huì)根據(jù)情況,進(jìn)行依次升級(jí)。

偏向鎖

假設(shè)男主是一個(gè)鎖, 女主是一個(gè)線程. 如果只有這一個(gè)線程來使用這個(gè)鎖, 那么男主女主即使不領(lǐng)證 結(jié)婚(避免了高成本操作), 也可以一直幸福的生活下去. 但是女配出現(xiàn)了, 也嘗試競爭男主, 此時(shí)不管領(lǐng)證結(jié)婚這個(gè)操作成本多高, 女主也勢必要把這個(gè)動(dòng)作 完成了, 讓女配死心

偏向鎖不是真的 "加鎖", 只是給對(duì)象頭中做一個(gè) "偏向鎖的標(biāo)記", 記錄這個(gè)鎖屬于哪個(gè)線程. 如果后續(xù)沒有其他線程來競爭該鎖, 那么就不用進(jìn)行其他同步操作了(避免了加鎖解鎖的開銷) 如果后續(xù)有其他線程來競爭該鎖(剛才已經(jīng)在鎖對(duì)象中記錄了當(dāng)前鎖屬于哪個(gè)線程了, 很容易識(shí)別 當(dāng)前申請(qǐng)鎖的線程是不是之前記錄的線程), 那就取消原來的偏向鎖狀態(tài), 進(jìn)入一般的輕量級(jí)鎖狀態(tài)

偏向鎖本質(zhì)上相當(dāng)于 "延遲加鎖" . 能不加鎖就不加鎖, 盡量來避免不必要的加鎖開銷. 但是該做的標(biāo)記還是得做的, 否則無法區(qū)分何時(shí)需要真正加鎖

偏向鎖不是真的加鎖, 而只是在鎖的對(duì)象頭中記錄一個(gè)標(biāo)記(記錄該鎖所屬的線程). 如果沒有其他線 程參與競爭鎖, 那么就不會(huì)真正執(zhí)行加鎖操作, 從而降低程序開銷. 一旦真的涉及到其他的線程競 爭, 再取消偏向鎖狀態(tài), 進(jìn)入輕量級(jí)鎖狀態(tài)

輕量級(jí)鎖

隨著其他線程進(jìn)入競爭, 偏向鎖狀態(tài)被消除, 進(jìn)入輕量級(jí)鎖狀態(tài)(自適應(yīng)的自旋鎖). 此處的輕量級(jí)鎖就是通過 CAS 來實(shí)現(xiàn).

通過 CAS 檢查并更新一塊內(nèi)存 (比如 null => 該線程引用)

如果更新成功, 則認(rèn)為加鎖成功

如果更新失敗, 則認(rèn)為鎖被占用, 繼續(xù)自旋式的等待(并不放棄 CPU).

自旋操作是一直讓 CPU 空轉(zhuǎn), 比較浪費(fèi) CPU 資源. 因此此處的自旋不會(huì)一直持續(xù)進(jìn)行, 而是達(dá)到一定的時(shí)間/重試次數(shù), 就不再自旋了. 也就是所謂的 "自適應(yīng)"

重量級(jí)鎖

如果競爭進(jìn)一步激烈, 自旋不能快速獲取到鎖狀態(tài), 就會(huì)膨脹為重量級(jí)鎖 此處的重量級(jí)鎖就是指用到內(nèi)核提供的 mutex .

執(zhí)行加鎖操作, 先進(jìn)入內(nèi)核態(tài).

在內(nèi)核態(tài)判定當(dāng)前鎖是否已經(jīng)被占用

如果該鎖沒有占用, 則加鎖成功, 并切換回用戶態(tài).

如果該鎖被占用, 則加鎖失敗. 此時(shí)線程進(jìn)入鎖的等待隊(duì)列, 掛起. 等待被操作系統(tǒng)喚醒.

經(jīng)歷了一系列的滄海桑田, 這個(gè)鎖被其他線程釋放了, 操作系統(tǒng)也想起了這個(gè)掛起的線程, 于是喚醒 這個(gè)線程, 嘗試重新獲取鎖

三、其他的優(yōu)化操作

鎖消除

編譯器+JVM 判斷鎖是否可消除. 如果可以, 就直接消除

有些應(yīng)用程序的代碼中, 用到了 synchronized, 但其實(shí)沒有在多線程環(huán)境下. (例如 StringBuffer)

StringBuffer sb = new StringBuffer();
sb.append("a");
sb.append("b");
sb.append("c");
sb.append("d");

此時(shí)每個(gè) append 的調(diào)用都會(huì)涉及加鎖和解鎖. 但如果只是在單線程中執(zhí)行這個(gè)代碼, 那么這些加 鎖解鎖操作是沒有必要的, 白白浪費(fèi)了一些資源開銷.

鎖粗化

一段邏輯中如果出現(xiàn)多次加鎖解鎖, 編譯器 + JVM 會(huì)自動(dòng)進(jìn)行鎖的粗化.

領(lǐng)導(dǎo), 給下屬交代工作任務(wù)

方式一:

打電話, 交代任務(wù)1, 掛電話.

打電話, 交代任務(wù)2, 掛電話.

打電話, 交代任務(wù)3, 掛電話

方式二:

打電話, 交代任務(wù)1, 任務(wù)2, 任務(wù)3, 掛電話

四、Callable 接口

Callable 是什么

Callable 是一個(gè) interface . 相當(dāng)于把線程封裝了一個(gè) "返回值". 方便程序猿借助多線程的方式計(jì)算 結(jié)果.

Callable 和 Runnable 相對(duì), 都是描述一個(gè) "任務(wù)". Callable 描述的是帶有返回值的任務(wù), Runnable 描述的是不帶返回值的任務(wù).Callable 通常需要搭配 FutureTask 來使用. FutureTask 用來保存 Callable 的返回結(jié)果. 因?yàn)?Callable 往往是在另一個(gè)線程中執(zhí)行的, 啥時(shí)候執(zhí)行完并不確定. FutureTask 就可以負(fù)責(zé)這個(gè)等待結(jié)果出來的工作.

代碼示例: 創(chuàng)建線程計(jì)算 1 + 2 + 3 + ... + 1000, 不使用 Callable 版本

public class Text {
 
    static class Result{
        public int sum = 0;
        public Object locker = new Object();
    }
 
    public static void main(String[] args) throws InterruptedException {
        Result result = new Result();
 
        Thread t = new Thread(){
            @Override
            public void run() {
                int sum = 0;
                for (int i = 0; i <=10000; i++){
                    sum += i;
                }
                result.sum = sum;
 
                synchronized (result.locker){
                    result.locker.notify();
                }
            }
        };
        t.start();
        synchronized (result.locker){
            while (result.sum == 0){
                result.locker.wait();
            }
        }
        System.out.println(result.sum);
    }
}

代碼示例: 創(chuàng)建線程計(jì)算 1 + 2 + 3 + ... + 1000, 使用 Callable 版本

import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
 
public class Text1 {
 
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        Callable<Integer> callable = new Callable<Integer>() {
            @Override
            public Integer call() throws Exception {
                int sum = 0;
                for (int i = 0; i <=1000; i++){
                    sum += i;
                }
                return sum;
            }
        };
        //由于Thread不能直接傳一個(gè)callable實(shí)例,就需要一個(gè)輔助類來包裝
        FutureTask<Integer> futureTask = new FutureTask<>(callable);
        Thread t = new Thread(futureTask);
        t.start();
        //嘗試在主線程獲取結(jié)果
        //如果FutureTask中的結(jié)果還沒生成。此時(shí)就會(huì)阻塞等待
        //一直等到最終的線程把這個(gè)結(jié)果算出來,get返回
        Integer result = futureTask.get();
        System.out.println(result);
    }
}

到此這篇關(guān)于Java 深入淺出分析Synchronized原理與Callable接口的文章就介紹到這了,更多相關(guān)Java Synchronized 內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Java StringBuilder類相關(guān)知識(shí)總結(jié)

    Java StringBuilder類相關(guān)知識(shí)總結(jié)

    這篇文章主要介紹了Java StringBuilder類相關(guān)知識(shí)總結(jié),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-02-02
  • Java實(shí)現(xiàn)的上傳并壓縮圖片功能【可等比例壓縮或原尺寸壓縮】

    Java實(shí)現(xiàn)的上傳并壓縮圖片功能【可等比例壓縮或原尺寸壓縮】

    這篇文章主要介紹了Java實(shí)現(xiàn)的上傳并壓縮圖片功能,可實(shí)現(xiàn)圖片的等比例壓縮或原尺寸壓縮,涉及java文件讀寫、轉(zhuǎn)換、傳輸?shù)认嚓P(guān)操作技巧,需要的朋友可以參考下
    2018-07-07
  • SpringBoot整合阿里云OSS對(duì)象存儲(chǔ)服務(wù)的實(shí)現(xiàn)

    SpringBoot整合阿里云OSS對(duì)象存儲(chǔ)服務(wù)的實(shí)現(xiàn)

    這篇文章主要介紹了SpringBoot整合阿里云OSS對(duì)象存儲(chǔ)服務(wù)的實(shí)現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2020-08-08
  • 聊聊@RequestParam,@PathParam,@PathVariable等注解的區(qū)別

    聊聊@RequestParam,@PathParam,@PathVariable等注解的區(qū)別

    這篇文章主要介紹了聊聊@RequestParam,@PathParam,@PathVariable等注解的區(qū)別,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過來看看吧
    2021-02-02
  • java中關(guān)于命令執(zhí)行匯總

    java中關(guān)于命令執(zhí)行匯總

    這篇文章主要介紹了java中關(guān)于命令執(zhí)行匯總,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • 用java實(shí)現(xiàn)冒泡排序算法

    用java實(shí)現(xiàn)冒泡排序算法

    兩兩比較待排序記錄的關(guān)鍵字,發(fā)現(xiàn)兩個(gè)記錄的次序相反時(shí)即進(jìn)行交換,直到?jīng)]有反序的記錄為止
    2013-01-01
  • spring boot在啟動(dòng)項(xiàng)目之后執(zhí)行的實(shí)現(xiàn)方法

    spring boot在啟動(dòng)項(xiàng)目之后執(zhí)行的實(shí)現(xiàn)方法

    在開發(fā)時(shí)有時(shí)候需要在整個(gè)應(yīng)用開始運(yùn)行時(shí)執(zhí)行一些特定代碼,比如初始化環(huán)境,下面這篇文章就來給大家介紹了關(guān)于spring boot在啟動(dòng)項(xiàng)目之后執(zhí)行自己要執(zhí)行的東西的實(shí)現(xiàn)方法,文中給出了詳細(xì)的示例代碼,需要的朋友可以參考下。
    2017-09-09
  • Java 基礎(chǔ)詳解(泛型、集合、IO、反射)

    Java 基礎(chǔ)詳解(泛型、集合、IO、反射)

    下面小編就為大家?guī)硪黄狫ava 基礎(chǔ)詳解(泛型、集合、IO、反射)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2017-10-10
  • 詳解SpringBoot健康檢查的實(shí)現(xiàn)原理

    詳解SpringBoot健康檢查的實(shí)現(xiàn)原理

    這篇文章主要介紹了詳解SpringBoot健康檢查的實(shí)現(xiàn)原理,幫助大家更好的理解和學(xué)習(xí)使用SpringBoot框架,感興趣的朋友可以了解下
    2021-03-03
  • Spring5使用JSR 330標(biāo)準(zhǔn)注解的方法

    Spring5使用JSR 330標(biāo)準(zhǔn)注解的方法

    從Spring3.0之后,除了Spring自帶的注解,我們也可以使用JSR330的標(biāo)準(zhǔn)注解,本文主要介紹了Spring5使用JSR 330標(biāo)準(zhǔn)注解,感興趣的可以了解一下
    2021-09-09

最新評(píng)論