成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

synchronized關(guān)鍵字使用詳解

Jeffrrey / 1564人閱讀

摘要:基本使用同步代碼塊同步代碼塊延時(shí)秒,方便后面測(cè)試作用代碼塊時(shí),方法中的,是指調(diào)用該方法的對(duì)象。那么這個(gè)時(shí)候使用關(guān)鍵字就需要注意了推薦使用同步代碼塊,同步的代碼塊中傳入外部定義的一個(gè)變量。

簡(jiǎn)述

計(jì)算機(jī)單線程在執(zhí)行任務(wù)時(shí),是嚴(yán)格按照程序的代碼邏輯,按照順序執(zhí)行的。因此單位時(shí)間內(nèi)能執(zhí)行的任務(wù)數(shù)量有限。為了能在相同的時(shí)間內(nèi)能執(zhí)行更多的任務(wù),就必須采用多線程的方式來(lái)執(zhí)行(注意:多線程模式無(wú)法減少單次任務(wù)的執(zhí)行時(shí)間)。但是引入了多線程之后,又帶來(lái)了線程安全的問(wèn)題。而為了解決線程安全的問(wèn)題,又引入了鎖的概念。java中常用的鎖有synchronizedlock兩種,本文我們來(lái)分析synchronized的具體用法和使用注意事項(xiàng)。

基本使用

同步代碼塊

/**
 * 同步代碼塊
 * @throws Exception
 */
public void synchronizedCode() {
    try {
        synchronized (this) {
            System.out.println(getCurrentTime() + ":I am synchronized Code");
            Thread.sleep(5000);//延時(shí)5秒,方便后面測(cè)試
        }
    } catch (Exception e) {
        e.printStackTrace();
    }
}

作用代碼塊時(shí),synchronized方法中的this,是指調(diào)用該方法的對(duì)象。需要主要的是,synchronized作用代碼塊時(shí),只會(huì)鎖住這一小塊代碼。代碼塊的上下部分的其他代碼在所有的線程仍然是能同時(shí)訪問(wèn)的。同時(shí)需要注意的是每個(gè)對(duì)象有用不同的鎖。即不會(huì)阻塞不同對(duì)象的調(diào)用。

同步方法

/**
  * 同步方法
  */
public synchronized void synchronizedMethod() {
    try {
        System.out.println(getCurrentTime() + ":I am synchronized method");
        Thread.sleep(5000);//延時(shí)5秒,方便后面測(cè)試
    } catch (Exception e) {
        e.printStackTrace();
    }
}

synchronized作用在方法上,其實(shí)是缺省了this關(guān)鍵字,實(shí)際上是synchronized(this)。this是指調(diào)用該方法的對(duì)象。此鎖也不會(huì)阻塞不同對(duì)象之間的調(diào)用。

同步靜態(tài)方法

/**
* 同步靜態(tài)方法
*/
public synchronized static void synchronizedStaticMethod() {
    try {
        System.out.println(getCurrentTime() + ":I am synchronized static method");
        Thread.sleep(5000);//延時(shí)5秒,方便后面測(cè)試
    } catch (Exception e) {
        e.printStackTrace();
    }
}

使用方式和作用普通方式相同,唯一需要注意的地方是此鎖所有對(duì)象共用,即不同對(duì)象之間會(huì)阻塞調(diào)用。

測(cè)試準(zhǔn)備

簡(jiǎn)單說(shuō)明一下:有一個(gè)線程池,在執(zhí)行多任務(wù)時(shí)使用。每個(gè)同步方法或者代碼塊中都有一個(gè)休眠5秒的動(dòng)作,利用打印時(shí)間加休眠來(lái)看線程之間是否有阻塞效果。然后有一個(gè)1秒打印一次時(shí)間的方法。

public class Synchronized {
    //打印時(shí)間時(shí)格式化
    public static final String timeFormat = "HH:mm:ss";
    //執(zhí)行多任務(wù)的線程池
    public static final ExecutorService executor = Executors.newFixedThreadPool(4);

    /**
     * 同步代碼塊
     * @throws Exception
     */
    public void synchronizedCode() {
        try {
            synchronized (this) {
                System.out.println(getCurrentTime() + ":I am synchronized Code");
                Thread.sleep(5000);//延時(shí)5秒,方便后面測(cè)試
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 同步方法
     */
    public synchronized void synchronizedMethod() {
        try {
            System.out.println(getCurrentTime() + ":I am synchronized method");
            Thread.sleep(5000);//延時(shí)5秒,方便后面測(cè)試
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 同步靜態(tài)方法
     */
    public synchronized static void synchronizedStaticMethod() {
        try {
            System.out.println(getCurrentTime() + ":I am synchronized static method");
            Thread.sleep(5000);//延時(shí)5秒,方便后面測(cè)試
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 循環(huán)打印時(shí)間
     */
    public static void printNumber() {
        executor.execute(new Runnable() {
            @Override
            public void run() {
                while (true) {
                    try {
                        printOnceASecond();
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
            }
        });
    }

    /**
     * 一秒打印一次時(shí)間
     *
     * @throws Exception
     */
    public static void printOnceASecond() throws Exception {
        System.out.println(getCurrentTime());
        Thread.sleep(1000);
    }

    /**
     * 獲取當(dāng)前時(shí)間
     *
     * @return
     */
    public static String getCurrentTime() {
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(timeFormat));
    }
}

OK,接下來(lái)我們就來(lái)測(cè)試下鎖的互斥性以及使用注意事項(xiàng)(都是多線程的情況下)。

開(kāi)始測(cè)試

同一個(gè)對(duì)象同步代碼塊

public static void main(String[] args) throws Exception {
    printNumber();//控制臺(tái)循環(huán)打印時(shí)間
    Synchronized es = new Synchronized();
    executor.execute(() -> es.synchronizedCode());
    executor.execute(() -> es.synchronizedCode());
}

execute

20:34:41:I am synchronized Code
20:34:41
20:34:42
20:34:43
20:34:44
20:34:45
20:34:46:I am synchronized Code

同步代碼塊中休眠5秒,導(dǎo)致另外一個(gè)線程阻塞5秒后再執(zhí)行。說(shuō)明代同步碼塊會(huì)阻塞同一個(gè)對(duì)象的不同線程之間的調(diào)用(同步方法和同步靜態(tài)方法也會(huì)阻塞同一個(gè)對(duì)象的不同線程之間的調(diào)用,此處省略測(cè)試代碼)

不同對(duì)象同步代碼塊

public static void main(String[] args) throws Exception {
    printNumber();//控制臺(tái)循環(huán)打印時(shí)間
    Synchronized es = new Synchronized();
    Synchronized es1 = new Synchronized();
    executor.execute(() -> es.synchronizedCode());
    executor.execute(() -> es1.synchronizedCode());
}

execute

20:44:34:I am synchronized Code
20:44:34:I am synchronized Code

由結(jié)果可以看出,不同對(duì)象之間代碼塊鎖互不影響(多線程也一樣)。原因是因?yàn)榇a塊中synchronized (this)

鎖的是當(dāng)前調(diào)用對(duì)象,不同對(duì)象之間不是同一把鎖,因此互不影響(同步方法原理也是如此,省略測(cè)試代碼)。

同一對(duì)象同步代碼塊和方法

public static void main(String[] args) throws Exception {
    printNumber();//控制臺(tái)循環(huán)打印時(shí)間
    Synchronized es = new Synchronized();
    executor.execute(() -> es.synchronizedCode());
    executor.execute(() -> es.synchronizedMethod());
}

execute

20:51:27:I am synchronized method
20:51:27
20:51:28
20:51:29
20:51:30
20:51:31
20:51:32:I am synchronized Code

因?yàn)橥酱a塊和同步方法,都是鎖當(dāng)前調(diào)用對(duì)象,因此執(zhí)行后打印上述結(jié)果應(yīng)該在意料之中?;谶@樣的特性,實(shí)際開(kāi)發(fā)在使用spring的時(shí)候就需要注意了,我們的bean交給spring容器管理之后,默認(rèn)都是單例的。那么這個(gè)時(shí)候使用synchronized關(guān)鍵字就需要注意了(推薦使用同步代碼塊,同步的代碼塊中傳入外部定義的一個(gè)變量)。

不同對(duì)象靜態(tài)同步方法

public static void main(String[] args) throws Exception {
    printNumber();//控制臺(tái)循環(huán)打印時(shí)間
    Synchronized es = new Synchronized();
    Synchronized es1 = new Synchronized();
    executor.execute(() -> es.synchronizedStaticMethod());
    executor.execute(() -> es1.synchronizedStaticMethod());
}

execute

21:05:39:I am synchronized static method
21:05:40
21:05:41
21:05:42
21:05:43
21:05:44:I am synchronized static method

由上述結(jié)果可以看出來(lái),靜態(tài)同步方法會(huì)阻塞所有的對(duì)象。原因是所有的靜態(tài)同步方法都是占用的同一把鎖。

相同對(duì)象同步方法和靜態(tài)同步方法

public static void main(String[] args) throws Exception {
    printNumber();//控制臺(tái)循環(huán)打印時(shí)間
    Synchronized es = new Synchronized();
    executor.execute(() -> es.synchronizedMethod());
    executor.execute(() -> es.synchronizedStaticMethod());
}

execute

21:11:03:I am synchronized static method
21:11:03:I am synchronized method

由此結(jié)果可以看出,同步方法和靜態(tài)同步方法之間不會(huì)造成阻塞的現(xiàn)象。因?yàn)樗麄冩i的對(duì)象不一樣。同步方法占用的鎖是調(diào)用對(duì)象,靜態(tài)同步方法鎖的是編譯后的class對(duì)象(類鎖)。

總結(jié)

同一個(gè)對(duì)象,同步方法、同步代碼塊之間互斥,同時(shí)和自己也互斥。靜態(tài)同步方法只和自己互斥

不同對(duì)象之間,同步方法、同步代碼塊不會(huì)互斥。靜態(tài)同步方法會(huì)互斥

synchronized在占用鎖時(shí),必須精確到某一個(gè)具體的對(duì)象

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/74420.html

相關(guān)文章

  • 一起學(xué)并發(fā)編程 - synchronized詳解

    摘要:每個(gè)對(duì)象只有一個(gè)鎖與之相關(guān)聯(lián)。實(shí)現(xiàn)同步則是以系統(tǒng)開(kāi)銷作為代價(jià),甚至可能造成死鎖,所以盡量避免濫用。這種機(jī)制確保了同一時(shí)刻該類實(shí)例,所有聲明為的函數(shù)中只有一個(gè)方法處于可執(zhí)行狀態(tài),從而有效避免了類成員變量訪問(wèn)沖突。 synchronized是JAVA語(yǔ)言的一個(gè)關(guān)鍵字,使用 synchronized 來(lái)修飾方法或代碼塊的時(shí)候,能夠保證多個(gè)線程中最多只有一個(gè)線程執(zhí)行該段代碼 ... 概述 ...

    acrazing 評(píng)論0 收藏0
  • Java中wait、notify、notifyAll使用詳解

    摘要:用法中規(guī)定,在調(diào)用者三個(gè)方法時(shí),當(dāng)前線程必須獲得對(duì)象鎖。作用方法作用線程自動(dòng)釋放占有的對(duì)象鎖,并等待。當(dāng)生產(chǎn)者生產(chǎn)了一個(gè)數(shù)據(jù)或者消費(fèi)者消費(fèi)了一個(gè)數(shù)據(jù)之后,使用方法來(lái)通知所有等待當(dāng)前對(duì)象鎖的線程,但是一次只會(huì)有一個(gè)等待的線程能拿到鎖。 基礎(chǔ)知識(shí) 首先我們需要知道,這幾個(gè)都是Object對(duì)象的方法。換言之,Java中所有的對(duì)象都有這些方法。 public final native void...

    rozbo 評(píng)論0 收藏0
  • Java synchronized 多線程同步問(wèn)題詳解

    摘要:同步代碼塊二類,鎖是小括號(hào)中的類對(duì)象對(duì)象。因?yàn)閷?duì)于同一個(gè)實(shí)例對(duì)象,各線程之間訪問(wèn)其中的同步方法是互斥的。優(yōu)化同步代碼塊的方式有,減少同步區(qū)域或減小鎖的范圍。 版權(quán)聲明:本文由吳仙杰創(chuàng)作整理,轉(zhuǎn)載請(qǐng)注明出處:https://segmentfault.com/a/1190000009225706 1. 引言 在 Java 多線程編程中,我們常需要考慮線程安全問(wèn)題,其中關(guān)鍵字 synchro...

    Eidesen 評(píng)論0 收藏0
  • 后臺(tái)開(kāi)發(fā)常問(wèn)面試題集錦(問(wèn)題搬運(yùn)工,附鏈接)

    摘要:基礎(chǔ)問(wèn)題的的性能及原理之區(qū)別詳解備忘筆記深入理解流水線抽象關(guān)鍵字修飾符知識(shí)點(diǎn)總結(jié)必看篇中的關(guān)鍵字解析回調(diào)機(jī)制解讀抽象類與三大特征時(shí)間和時(shí)間戳的相互轉(zhuǎn)換為什么要使用內(nèi)部類對(duì)象鎖和類鎖的區(qū)別,,優(yōu)缺點(diǎn)及比較提高篇八詳解內(nèi)部類單例模式和 Java基礎(chǔ)問(wèn)題 String的+的性能及原理 java之yield(),sleep(),wait()區(qū)別詳解-備忘筆記 深入理解Java Stream流水...

    spacewander 評(píng)論0 收藏0
  • 后臺(tái)開(kāi)發(fā)常問(wèn)面試題集錦(問(wèn)題搬運(yùn)工,附鏈接)

    摘要:基礎(chǔ)問(wèn)題的的性能及原理之區(qū)別詳解備忘筆記深入理解流水線抽象關(guān)鍵字修飾符知識(shí)點(diǎn)總結(jié)必看篇中的關(guān)鍵字解析回調(diào)機(jī)制解讀抽象類與三大特征時(shí)間和時(shí)間戳的相互轉(zhuǎn)換為什么要使用內(nèi)部類對(duì)象鎖和類鎖的區(qū)別,,優(yōu)缺點(diǎn)及比較提高篇八詳解內(nèi)部類單例模式和 Java基礎(chǔ)問(wèn)題 String的+的性能及原理 java之yield(),sleep(),wait()區(qū)別詳解-備忘筆記 深入理解Java Stream流水...

    xfee 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<