自拍偷在线精品自拍偷,亚洲欧美中文日韩v在线观看不卡

你真的了解Java監(jiān)視器鎖和Synchronized關(guān)鍵字嗎?

開(kāi)發(fā) 前端
本文介紹了Java中的Synchronized關(guān)鍵字及其基本用法、實(shí)現(xiàn)原理和進(jìn)階使用技巧。需要注意的是,在編寫(xiě)多線(xiàn)程程序時(shí),我們應(yīng)該注意避免常見(jiàn)的錯(cuò)誤和陷阱,以確保程序的正確性和效率。

在Java中,多線(xiàn)程并發(fā)訪(fǎng)問(wèn)共享資源是一個(gè)經(jīng)常遇到的問(wèn)題。為了保證數(shù)據(jù)的正確性和一致性,在多線(xiàn)程編程中需要使用同步機(jī)制來(lái)實(shí)現(xiàn)對(duì)臨界資源的互斥訪(fǎng)問(wèn)。Java中的synchronized關(guān)鍵字提供了一種簡(jiǎn)單而有效的同步機(jī)制,可以用于保護(hù)臨界區(qū)。

臨界區(qū)的概念

在多線(xiàn)程的程序中,臨界區(qū)指的是一段需要互斥訪(fǎng)問(wèn)的代碼塊,即同一時(shí)間只能由一個(gè)線(xiàn)程執(zhí)行的代碼。在這段代碼執(zhí)行期間,如果其他線(xiàn)程試圖訪(fǎng)問(wèn)該代碼塊,那么它們會(huì)被阻塞,直到當(dāng)前線(xiàn)程釋放了鎖。

相對(duì)應(yīng)地,非臨界區(qū)指的是所有不需要互斥訪(fǎng)問(wèn)的代碼,也就是說(shuō),多個(gè)線(xiàn)程可以同時(shí)執(zhí)行該代碼,而不會(huì)有數(shù)據(jù)競(jìng)爭(zhēng)或并發(fā)問(wèn)題。

在Java中,synchronized關(guān)鍵字用于保證對(duì)臨界區(qū)代碼的互斥訪(fǎng)問(wèn),使得在任何時(shí)刻只有一個(gè)線(xiàn)程可以執(zhí)行該代碼。但是,synchronized不能保證對(duì)非臨界區(qū)代碼的可見(jiàn)性和有序性,因此,在修改共享變量的值、檢查共享變量的狀態(tài)等操作時(shí),需要注意使用volatile關(guān)鍵字或其他同步機(jī)制來(lái)確保線(xiàn)程之間的正確協(xié)作。

1、監(jiān)視器鎖和Java對(duì)象

在Java中,每個(gè)對(duì)象都有一個(gè)關(guān)聯(lián)的監(jiān)視器鎖,也稱(chēng)為內(nèi)部鎖或隱式鎖。每個(gè)鎖都有一個(gè)相關(guān)的等待集(Wait Set)和喚醒集(Notification Set)。當(dāng)一個(gè)線(xiàn)程試圖獲取該對(duì)象的鎖時(shí),如果該鎖已經(jīng)被其他線(xiàn)程持有,則該線(xiàn)程將被阻塞,直到該鎖被釋放。當(dāng)一個(gè)線(xiàn)程持有該鎖時(shí),其他線(xiàn)程試圖獲取該鎖時(shí)會(huì)進(jìn)入鎖的等待集,并在該鎖被釋放并通知時(shí)嘗試重新獲取鎖。

2、synchronized關(guān)鍵字的使用

synchronized關(guān)鍵字可以用于控制對(duì)臨界資源的訪(fǎng)問(wèn)。它可以用于方法上或代碼塊上,并將其作為一個(gè)鎖來(lái)進(jìn)行同步。當(dāng)一個(gè)線(xiàn)程執(zhí)行synchronized方法或代碼塊時(shí),它將獲取與該方法或代碼塊關(guān)聯(lián)的對(duì)象的鎖。如果其他線(xiàn)程試圖獲取相同對(duì)象上的鎖,則它們將被阻塞,直到該鎖被釋放。

下面是一個(gè)簡(jiǎn)單的示例,展示了如何使用synchronized來(lái)實(shí)現(xiàn)對(duì)臨界資源的同步訪(fǎng)問(wèn):

public class Counter {
    private int count = 0;

    public synchronized void increment() {
        count++;
    }

    public synchronized void decrement() {
        count--;
    }

    public synchronized int getCount() {
        return count;
    }
}

在這個(gè)例子中,increment、decrement和getCount方法都被聲明為synchronized,并且它們都操作Counter對(duì)象的共享狀態(tài)。當(dāng)一個(gè)線(xiàn)程調(diào)用其中一個(gè)方法時(shí),它將獲取Counter對(duì)象的鎖,并允許該線(xiàn)程訪(fǎng)問(wèn)其中的代碼。其他線(xiàn)程將被阻塞,直到鎖被釋放。

需要注意的是,在Java中,每個(gè)對(duì)象只有一個(gè)鎖。因此,如果一個(gè)類(lèi)中有多個(gè)同步方法或代碼塊,它們都將競(jìng)爭(zhēng)同一個(gè)鎖。這意味著,如果多個(gè)線(xiàn)程同時(shí)調(diào)用這些方法或代碼塊,它們只能以串行方式執(zhí)行,從而降低了并發(fā)效率。因此,我們應(yīng)該盡可能地減少同步代碼塊的大小和范圍,以便使其他線(xiàn)程能夠更快地訪(fǎng)問(wèn)臨界資源。

3、監(jiān)視器鎖原理

在JVM層面,每個(gè)對(duì)象都有一個(gè)關(guān)聯(lián)的監(jiān)視器鎖。當(dāng)一個(gè)線(xiàn)程試圖獲取該對(duì)象的鎖時(shí),如果該鎖已經(jīng)被其他線(xiàn)程持有,則該線(xiàn)程將進(jìn)入阻塞狀態(tài)。

在字節(jié)碼層面,synchronized關(guān)鍵字通過(guò)monitorenter和monitorexit指令來(lái)實(shí)現(xiàn)對(duì)臨界資源的同步訪(fǎng)問(wèn)。這兩個(gè)指令可以分別看作是獲取鎖和釋放鎖的操作。當(dāng)一個(gè)線(xiàn)程執(zhí)行到monitorenter指令時(shí),它將嘗試獲取對(duì)象的鎖。如果該鎖已經(jīng)被其他線(xiàn)程持有,則該線(xiàn)程將進(jìn)入阻塞狀態(tài)。當(dāng)線(xiàn)程執(zhí)行到monitorexit指令時(shí),它將釋放對(duì)象的鎖,并喚醒等待集中的線(xiàn)程來(lái)競(jìng)爭(zhēng)鎖。

在上面的代碼示例中,increment、decrement和getCount方法的實(shí)現(xiàn)都包含一個(gè)同步塊,其中使用了synchronized(this)來(lái)獲取Counter對(duì)象的鎖。當(dāng)線(xiàn)程執(zhí)行到這個(gè)同步塊時(shí),它會(huì)執(zhí)行monitorenter指令來(lái)獲取鎖,并在退出同步塊時(shí)執(zhí)行monitorexit指令來(lái)釋放鎖。需要注意的是,如果多個(gè)線(xiàn)程同時(shí)調(diào)用這些方法,并且它們持有不同的Counter對(duì)象,那么它們將競(jìng)爭(zhēng)不同的鎖,并且能夠并發(fā)地執(zhí)行。因此,在編寫(xiě)多線(xiàn)程程序時(shí),應(yīng)該盡量使用局部變量來(lái)限制鎖的范圍,以避免多個(gè)線(xiàn)程競(jìng)爭(zhēng)同一個(gè)鎖而導(dǎo)致性能下降。

4、synchronized關(guān)鍵字的進(jìn)階使用技巧

除了基本的同步機(jī)制外,synchronized關(guān)鍵字還提供了一些進(jìn)階的使用技巧,可以更加靈活地控制對(duì)臨界資源的訪(fǎng)問(wèn)。下面介紹幾種常見(jiàn)的技巧:

(1)synchronized塊

除了將synchronized關(guān)鍵字用于方法聲明外,它還可以用于代碼塊。在這種情況下,同步塊的范圍可以更加靈活,從而使得多個(gè)線(xiàn)程可以并發(fā)地執(zhí)行非臨界代碼。下面是一個(gè)示例代碼:

public class Counter {
    private int count = 0;
    private Object lock = new Object();

    public void increment() {
        synchronized (lock) {
            count++;
        }
    }

    public void decrement() {
        synchronized (lock) {
            count--;
        }
    }

    public int getCount() {
        synchronized (lock) {
            return count;
        }
    }
}

在這個(gè)例子中,我們使用了一個(gè)Object對(duì)象作為鎖,并在每個(gè)方法內(nèi)部使用synchronized(lock)來(lái)實(shí)現(xiàn)同步訪(fǎng)問(wèn)。由于鎖的范圍被限制在同步塊內(nèi)部,因此多個(gè)線(xiàn)程可以并發(fā)地執(zhí)行非臨界代碼。

需要注意的是,在使用synchronized塊時(shí),我們應(yīng)該盡量使用局部變量或私有實(shí)例變量作為鎖對(duì)象,以避免和其他類(lèi)共享鎖對(duì)象而導(dǎo)致死鎖等問(wèn)題。

(2)synchronized靜態(tài)方法

除了將synchronized關(guān)鍵字用于實(shí)例方法外,它還可以用于靜態(tài)方法。在這種情況下,鎖對(duì)象是該類(lèi)的Class對(duì)象。下面是一個(gè)示例代碼:

public class Counter {
    private static int count = 0;

    public static synchronized void increment() {
        count++;
    }

    public static synchronized void decrement() {
        count--;
    }

    public static synchronized int getCount() {
        return count;
    }
}

在這個(gè)例子中,我們將synchronized關(guān)鍵字用于靜態(tài)方法,并使用類(lèi)的Class對(duì)象作為鎖。由于鎖對(duì)象是唯一的,因此多個(gè)線(xiàn)程將串行地執(zhí)行方法。

需要注意的是,在使用synchronized靜態(tài)方法時(shí),我們應(yīng)該盡可能地避免阻塞和競(jìng)爭(zhēng),以提高程序的并發(fā)性能。

(3)可重入性

Java的synchronized關(guān)鍵字實(shí)現(xiàn)了可重入性,也就是說(shuō),如果一個(gè)線(xiàn)程已經(jīng)持有了某個(gè)對(duì)象的鎖,那么它可以再次獲取該對(duì)象的鎖,從而繼續(xù)訪(fǎng)問(wèn)臨界資源。這種機(jī)制可以有效地避免死鎖和餓死等問(wèn)題。

在上面代碼示例中,increment方法調(diào)用了decrement方法,并且兩個(gè)方法都使用了synchronized關(guān)鍵字來(lái)同步訪(fǎng)問(wèn)。由于這兩個(gè)方法都被聲明為synchronized,因此它們都需要獲取Counter對(duì)象的鎖來(lái)執(zhí)行。如果一個(gè)線(xiàn)程已經(jīng)持有了該鎖,那么它可以繼續(xù)獲取該鎖而不會(huì)被阻塞,從而避免了死鎖問(wèn)題。

需要注意的是,在使用可重入性時(shí),我們應(yīng)該盡可能地避免嵌套鎖和遞歸鎖,以避免死鎖和性能問(wèn)題。

(4)volatile關(guān)鍵字

雖然synchronized關(guān)鍵字可以保證對(duì)臨界資源的同步訪(fǎng)問(wèn),但它并不能保證對(duì)非臨界資源的可見(jiàn)性。換句話(huà)說(shuō),如果一個(gè)線(xiàn)程修改了一個(gè)變量的值,但該變量沒(méi)有被聲明為volatile或使用同步機(jī)制進(jìn)行同步訪(fǎng)問(wèn),那么其他線(xiàn)程可能無(wú)法看到該變量的新值。

下面是一個(gè)示例代碼:

public class Counter {
    private int count = 0;
    private boolean flag = false;

    public void increment() {
        count++;
        flag = true;
    }

    public int getCount() {
        if (flag) {
            return count;
        } else {
            return -1;
        }
    }
}

在這個(gè)例子中,increment方法將count變量的值增加1,并設(shè)置flag變量的值為true。getCount方法檢查flag變量的值,如果為true,則返回count變量的值;否則返回-1。由于flag變量沒(méi)有被聲明為volatile或使用同步機(jī)制進(jìn)行同步訪(fǎng)問(wèn),因此它的值可能無(wú)法被其他線(xiàn)程看到,從而導(dǎo)致getCount方法返回錯(cuò)誤的結(jié)果。

為了解決這個(gè)問(wèn)題,我們可以使用volatile關(guān)鍵字來(lái)保證對(duì)變量的可見(jiàn)性和有序性。下面是一個(gè)修改后的示例代碼:

public class Counter {
    private volatile int count = 0;
    private volatile boolean flag = false;

    public void increment() {
        count++;
        flag = true;
    }

    public int getCount() {
        if (flag) {
            return count;
        } else {
            return -1;
        }
    }
}

在這個(gè)例子中,我們將count和flag變量都聲明為volatile,以保證它們的可見(jiàn)性和有序性。這樣,當(dāng)一個(gè)線(xiàn)程修改了count或flag變量的值時(shí),其他線(xiàn)程可以立即看到該變化。

需要注意的是,在使用volatile關(guān)鍵字時(shí),我們應(yīng)該避免使用復(fù)合操作以及依賴(lài)于先前狀態(tài)的操作,以確保對(duì)變量的操作的原子性和一致性。

5、一些常見(jiàn)問(wèn)題

在使用synchronized關(guān)鍵字時(shí),我們應(yīng)該避免以下常見(jiàn)的錯(cuò)誤和陷阱:

(1)不要過(guò)度同步

在多線(xiàn)程編程中,過(guò)度同步可能會(huì)導(dǎo)致死鎖、饑餓等問(wèn)題,并且降低程序的并發(fā)性能。因此,我們應(yīng)該盡可能地減少同步代碼塊的大小和范圍,以便使其他線(xiàn)程能夠更快地訪(fǎng)問(wèn)非臨界資源。

(2)避免死鎖

死鎖是多線(xiàn)程編程中常見(jiàn)的問(wèn)題之一,它會(huì)導(dǎo)致多個(gè)線(xiàn)程相互等待彼此釋放鎖而無(wú)法繼續(xù)執(zhí)行。避免死鎖的關(guān)鍵是正確地掌握鎖的粒度和順序,并盡可能地減少鎖的嵌套層數(shù)。

(3)善用Wait和Notify

Java提供了Wait和Notify機(jī)制來(lái)協(xié)調(diào)多個(gè)線(xiàn)程對(duì)共享資源的訪(fǎng)問(wèn)。在使用這些機(jī)制時(shí),我們應(yīng)該注意正確地使用鎖對(duì)象,并避免出現(xiàn)死鎖、饑餓等問(wèn)題。

(4)不要依賴(lài)于原子性

雖然synchronized關(guān)鍵字可以保證對(duì)臨界資源的同步訪(fǎng)問(wèn),但它并不能保證對(duì)非臨界資源的原子性操作。因此,在進(jìn)行復(fù)合操作或依賴(lài)于先前狀態(tài)的操作時(shí),我們應(yīng)該使用原子類(lèi)或其他同步工具來(lái)確保操作的原子性和一致性。

6、總結(jié)

本文介紹了Java中的synchronized關(guān)鍵字及其基本用法、實(shí)現(xiàn)原理和進(jìn)階使用技巧。需要注意的是,在編寫(xiě)多線(xiàn)程程序時(shí),我們應(yīng)該注意避免常見(jiàn)的錯(cuò)誤和陷阱,以確保程序的正確性和效率。

責(zé)任編輯:姜華 來(lái)源: 今日頭條
相關(guān)推薦

2023-11-07 07:36:58

JavaThis關(guān)鍵字

2021-03-10 15:59:39

JavaSynchronize并發(fā)編程

2019-12-20 15:19:41

Synchroinze線(xiàn)程安全

2024-03-15 15:12:27

關(guān)鍵字底層代碼

2017-05-27 20:59:30

Java多線(xiàn)程synchronize

2024-11-20 15:55:57

線(xiàn)程Java開(kāi)發(fā)

2021-11-26 08:07:16

MySQL SQL 語(yǔ)句數(shù)據(jù)庫(kù)

2022-01-26 00:03:00

關(guān)鍵字線(xiàn)程JVM

2023-12-11 13:59:00

YieldPython生成器函數(shù)

2009-08-12 13:37:01

Java synchr

2022-03-14 07:53:27

ELTETL大數(shù)據(jù)

2021-01-12 09:22:18

Synchronize線(xiàn)程開(kāi)發(fā)技術(shù)

2021-08-15 08:11:54

AndroidSynchronize關(guān)鍵字

2022-07-26 00:00:22

HTAP系統(tǒng)數(shù)據(jù)庫(kù)

2014-04-17 16:42:03

DevOps

2009-06-29 18:26:11

Java多線(xiàn)程Synchronize同步類(lèi)

2010-10-20 13:15:25

SQL Server復(fù)

2018-12-05 10:10:23

Windows 10設(shè)置監(jiān)視器

2021-01-15 07:44:21

SQL注入攻擊黑客

2021-11-09 09:48:13

Logging python模塊
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號(hào)