第七色在线视频,2021少妇久久久久久久久久,亚洲欧洲精品成人久久av18,亚洲国产精品特色大片观看完整版,孙宇晨将参加特朗普的晚宴

synchronized 關(guān)鍵字

1. 前言

本節(jié)內(nèi)容主要是對(duì) synchronized 關(guān)鍵字的使用進(jìn)行講解,具體內(nèi)容點(diǎn)如下:

  • 了解 synchronized 關(guān)鍵字的概念,從總體層面對(duì) synchronized 關(guān)鍵字進(jìn)行了解,是我們本節(jié)課程的基礎(chǔ)知識(shí);
  • 了解 synchronized 關(guān)鍵字的作用,知道 synchronized 關(guān)鍵字使用的意義,使我們學(xué)習(xí)本節(jié)內(nèi)容的出發(fā)點(diǎn);
  • 掌握 synchronized 關(guān)鍵字的 3 中使用方式,使我們本節(jié)課程的核心內(nèi)容,所有的內(nèi)容講解都是圍繞這一知識(shí)點(diǎn)進(jìn)行的;
  • 了解 synchronized 關(guān)鍵字的內(nèi)存語(yǔ)義,將 synchronized 關(guān)鍵字與 Java 的線程內(nèi)存模型進(jìn)行關(guān)聯(lián),更好的了解 synchronized 關(guān)鍵字的作用及意義,為本節(jié)重點(diǎn)內(nèi)容。

2. synchronized 關(guān)鍵字介紹

概念:synchronized 同步塊是 Java 提供的一種原子性內(nèi)置鎖,Java 中的每個(gè)對(duì)象都可以把它當(dāng)作一個(gè)同步鎖來(lái)使用,這些 Java 內(nèi)置的使用者看不到的鎖被稱為內(nèi)部鎖,也叫作監(jiān)視器鎖。

線程的執(zhí)行:代碼在進(jìn)入 synchronized 代碼塊前會(huì)自動(dòng)獲取內(nèi)部鎖,這時(shí)候其他線程訪問(wèn)該同步代碼塊時(shí)會(huì)被阻塞掛起。拿到內(nèi)部鎖的線程會(huì)在正常退出同步代碼塊或者拋出異常后或者在同步塊內(nèi)調(diào)用了該內(nèi)置鎖資源的 wait 系列方法時(shí)釋放該內(nèi)置鎖。

內(nèi)置鎖:即排它鎖,也就是當(dāng)一個(gè)線程獲取這個(gè)鎖后,其他線程必須等待該線程釋放鎖后才能獲取該鎖。

Tips:由于 Java 中的線程是與操作系統(tǒng)的原生線程一一對(duì)應(yīng)的,所以當(dāng)阻塞一個(gè)線程時(shí),需要從用戶態(tài)切換到內(nèi)核態(tài)執(zhí)行阻塞操作,這是很耗時(shí)的操作,而 synchronized 的使用就會(huì)導(dǎo)致上下文切換。
后續(xù)章節(jié)我們會(huì)引入 Lock 接口和 ReadWriteLock 接口,能在一定場(chǎng)景下很好地避免 synchronized 關(guān)鍵字導(dǎo)致的上下文切換問(wèn)題。

3. synchronized 關(guān)鍵字的作用

作用:在并發(fā)編程中存在線程安全問(wèn)題,使用 synchronized 關(guān)鍵字能夠有效的避免多線程環(huán)境下的線程安全問(wèn)題,線程安全問(wèn)題主要考慮以下三點(diǎn):

  • 存在共享數(shù)據(jù),共享數(shù)據(jù)是對(duì)多線程可見(jiàn)的,所有的線程都有權(quán)限對(duì)共享數(shù)據(jù)進(jìn)行操作;
  • 多線程共同操作共享數(shù)據(jù)。關(guān)鍵字 synchronized 可以保證在同一時(shí)刻,只有一個(gè)線程可以執(zhí)行某個(gè)同步方法或者同步代碼塊,同時(shí) synchronized 關(guān)鍵字可以保證一個(gè)線程變化的可見(jiàn)性;
  • 多線程共同操作共享數(shù)據(jù)且涉及增刪改操作。如果只是查詢操作,是不需要使用 synchronized 關(guān)鍵字的,在涉及到增刪改操作時(shí),為了保證數(shù)據(jù)的準(zhǔn)確性,可以選擇使用 synchronized 關(guān)鍵字。

4. synchronized 的三種使用方式

Java 中每一個(gè)對(duì)象都可以作為鎖,這是 synchronized 實(shí)現(xiàn)同步的基礎(chǔ)。synchronized 的三種使用方式如下:

  • 普通同步方法(實(shí)例方法):鎖是當(dāng)前實(shí)例對(duì)象 ,進(jìn)入同步代碼前要獲得當(dāng)前實(shí)例的鎖;
  • 靜態(tài)同步方法:鎖是當(dāng)前類的 class 對(duì)象 ,進(jìn)入同步代碼前要獲得當(dāng)前類對(duì)象的鎖;
  • 同步方法塊:鎖是括號(hào)里面的對(duì)象,對(duì)給定對(duì)象加鎖,進(jìn)入同步代碼庫(kù)前要獲得給定對(duì)象的鎖。

接下來(lái)會(huì)對(duì)這三種使用方式進(jìn)行詳細(xì)的講解,也是本節(jié)課程的核心內(nèi)容。

5. synchronized 作用于實(shí)例方法

為了更加深刻的體會(huì) synchronized 作用于實(shí)例方法的使用,我們先來(lái)設(shè)計(jì)一個(gè)場(chǎng)景,并根據(jù)要求,通過(guò)代碼的實(shí)例進(jìn)行實(shí)現(xiàn)。

場(chǎng)景設(shè)計(jì)

  • 創(chuàng)建兩個(gè)線程,分別設(shè)置線程名稱為 threadOne 和 threadTwo;
  • 創(chuàng)建一個(gè)共享的 int 數(shù)據(jù)類型的 count,初始值為 0;
  • 兩個(gè)線程同時(shí)對(duì)該共享數(shù)據(jù)進(jìn)行增 1 操作,每次操作 count 的值增加 1;
  • 對(duì)于 count 數(shù)值加 1 的操作,請(qǐng)創(chuàng)建一個(gè)單獨(dú)的 increase 方法進(jìn)行實(shí)現(xiàn);
  • increase 方法中,先打印進(jìn)入的線程名稱,然后進(jìn)行 1000 毫秒的 sleep,每次加 1 操作后,打印操作的線程名稱和 count 的值;
  • 運(yùn)行程序,觀察打印結(jié)果。

結(jié)果預(yù)期:因?yàn)?increase 方法有兩個(gè)打印的語(yǔ)句,不會(huì)出現(xiàn) threadOne 和 threadTwo 的交替打印,一個(gè)線程執(zhí)行完 2 句打印之后,才能給另外一個(gè)線程執(zhí)行。

實(shí)例

public class DemoTest extends Thread {
    //共享資源
    static int count = 0;

    /**
     * synchronized 修飾實(shí)例方法
     */
    public synchronized void increase() throws InterruptedException {
	    sleep(1000);
	    count++;
	    System.out.println(Thread.currentThread().getName() + ": " + count);
	}
    @Override
    public void run() {
        try {
            increase();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
    public static void main(String[] args) throws InterruptedException {
        DemoTest test = new DemoTest();
        Thread t1 = new Thread(test);
        Thread t2 = new Thread(test);
        t1.setName("threadOne");
        t2.setName("threadTwo");
        t1. start();
        t2. start();
    }

結(jié)果驗(yàn)證

threadTwo 獲取到鎖,其他線程在我執(zhí)行完畢之前,不可進(jìn)入。
threadTwo: 1
threadOne 獲取到鎖,其他線程在我執(zhí)行完畢之前,不可進(jìn)入。
threadOne: 2

從結(jié)果可以看出,threadTwo 進(jìn)入該方法后,休眠了 1000 毫秒,此時(shí)線程 threadOne 依然沒(méi)有辦法進(jìn)入,因?yàn)?threadTwo 已經(jīng)獲取了鎖,threadOne 只能等待 threadTwo 執(zhí)行完畢后才可進(jìn)入執(zhí)行,這就是 synchronized 修飾實(shí)例方法的使用。

Tips:仔細(xì)看 DemoTest test = new DemoTest () 這就話,我們創(chuàng)建了一個(gè) DemoTest 的實(shí)例對(duì)象,對(duì)于修飾普通方法,synchronized 關(guān)鍵字的鎖即為 test 這個(gè)實(shí)例對(duì)象。

6. synchronized 作用于靜態(tài)方法

Tips:對(duì)于 synchronized 作用于靜態(tài)方法,鎖為當(dāng)前的 class,要明白與修飾普通方法的區(qū)別,普通方法的鎖為創(chuàng)建的實(shí)例對(duì)象。為了更好地理解,我們對(duì)第 5 點(diǎn)講解的代碼進(jìn)行微調(diào),然后觀察打印結(jié)果。

代碼修改:其他代碼不變,只修改如下部分代碼。

  • 新增創(chuàng)建一個(gè)實(shí)例對(duì)象 testNew ;
  • 將線程 2 設(shè)置為 testNew 。
public static void main(String[] args) throws InterruptedException {
        DemoTest test = new DemoTest();
        DemoTest testNew = new DemoTest();
        Thread t1 = new Thread(test);
        Thread t2 = new Thread(testNew);
        t1.setName("threadOne");
        t2.setName("threadTwo");
        t1. start();
        t2. start();
    }

結(jié)果驗(yàn)證

threadTwo 獲取到鎖,其他線程在我執(zhí)行完畢之前,不可進(jìn)入。
threadOne 獲取到鎖,其他線程在我執(zhí)行完畢之前,不可進(jìn)入。
threadTwo: 1
threadOne: 2

結(jié)果分析:我們發(fā)現(xiàn) threadTwo 和 threadOne 同時(shí)進(jìn)入了該方法,為什么會(huì)出現(xiàn)這種問(wèn)題呢?
因?yàn)槲覀兇舜蔚男薷氖切略隽?testNew 這個(gè)實(shí)例對(duì)象,也就是說(shuō),threadTwo 的鎖是 testNew ,threadOne 的鎖是 test。

兩個(gè)線程持有兩個(gè)不同的鎖,不會(huì)產(chǎn)生互相 block。相信講到這里,同學(xué)對(duì)實(shí)例對(duì)象鎖的作用也了解了,那么我們?cè)俅螌?increase 方法進(jìn)行修改,將其修改成靜態(tài)方法,然后輸出結(jié)果。

代碼修改

public static synchronized void increase() throws InterruptedException {
        System.out.println(Thread.currentThread().getName() + "獲取到鎖,其他線程在我執(zhí)行完畢之前,不可進(jìn)入。" );
        sleep(1000);
        count++;
        System.out.println(Thread.currentThread().getName() + ": " + count);
    }

結(jié)果驗(yàn)證

threadOne獲取到鎖,其他線程在我執(zhí)行完畢之前,不可進(jìn)入。
threadOne: 1
threadTwo獲取到鎖,其他線程在我執(zhí)行完畢之前,不可進(jìn)入。
threadTwo: 2

結(jié)果分析:我們看到,結(jié)果又恢復(fù)了正常,為什么會(huì)這樣?
關(guān)鍵的原因在于,synchronized 修飾靜態(tài)方法,鎖為當(dāng)前 class,即 DemoTest.class。

public class DemoTest extends Thread {}

無(wú)論 threadOne 和 threadTwo 如何進(jìn)行 new 實(shí)例對(duì)象的創(chuàng)建,也不會(huì)改變鎖是 DemoTest.class 的這一事實(shí)。

7. synchronized 作用于同步代碼塊

Tips:對(duì)于 synchronized 作用于同步代碼,鎖為任何我們創(chuàng)建的對(duì)象,只要是個(gè)對(duì)象即可,如 new Object () 可以作為鎖,new String () 也可作為鎖,當(dāng)然如果傳入 this,那么此時(shí)代表當(dāng)前對(duì)象。

我們將代碼恢復(fù)到第 5 點(diǎn)的知識(shí),然后在第 5 點(diǎn)知識(shí)的基礎(chǔ)上,再次對(duì)代碼進(jìn)行如下修改:

代碼修改

	/**
     * synchronized 修飾實(shí)例方法
     */
    static final Object objectLock = new Object(); //創(chuàng)建一個(gè)對(duì)象鎖
    public static void increase() throws InterruptedException {
        System.out.println(Thread.currentThread().getName() + "獲取到鎖,其他線程在我執(zhí)行完畢之前,不可進(jìn)入。" );
        synchronized (objectLock) {
            sleep(1000);
            count++;
            System.out.println(Thread.currentThread().getName() + ": " + count);
        }
    }

代碼解析:我們創(chuàng)建了一個(gè) objectLock 作為對(duì)象鎖,除了第一句打印語(yǔ)句,讓后三句代碼加入了 synchronized 同步代碼塊,當(dāng) threadOne 進(jìn)入時(shí),threadTwo 不可進(jìn)入后三句代碼的執(zhí)行。

結(jié)果驗(yàn)證

threadOne 獲取到鎖,其他線程在我執(zhí)行完畢之前,不可進(jìn)入。
threadTwo 獲取到鎖,其他線程在我執(zhí)行完畢之前,不可進(jìn)入。
threadOne: 1
threadTwo: 2

8. 小結(jié)

本節(jié)內(nèi)容的核心即 synchronized 關(guān)鍵字的 3 種使用方式,這是必須要掌握的問(wèn)題。除此之外,不同的使用方法獲取到的鎖的類型是不一樣的,這是本節(jié)內(nèi)容的重點(diǎn),也是必須要掌握的知識(shí)。

對(duì) synchronized 關(guān)鍵字的熟練使用,是并發(fā)編程中的一項(xiàng)重要技能。