真实的国产乱ⅩXXX66竹夫人,五月香六月婷婷激情综合,亚洲日本VA一区二区三区,亚洲精品一区二区三区麻豆

成都創(chuàng)新互聯(lián)網(wǎng)站制作重慶分公司

線程安全和synchronized關(guān)鍵字-創(chuàng)新互聯(lián)

一,線程安全的引入 1.示例

多線程在多進(jìn)程的基礎(chǔ)上更好解決了并發(fā)問題,但由于一個(gè)進(jìn)程內(nèi)的多個(gè)線程是資源共享的,就會出現(xiàn)多個(gè)線程在并發(fā)執(zhí)行的時(shí)候造成內(nèi)存中數(shù)據(jù)的混亂。

成都創(chuàng)新互聯(lián)為企業(yè)級客戶提高一站式互聯(lián)網(wǎng)+設(shè)計(jì)服務(wù),主要包括成都網(wǎng)站建設(shè)、成都網(wǎng)站制作、重慶APP軟件開發(fā)重慶小程序開發(fā)公司、宣傳片制作、LOGO設(shè)計(jì)等,幫助客戶快速提升營銷能力和企業(yè)形象,創(chuàng)新互聯(lián)各部門都有經(jīng)驗(yàn)豐富的經(jīng)驗(yàn),可以確保每一個(gè)作品的質(zhì)量和創(chuàng)作周期,同時(shí)每年都有很多新員工加入,為我們帶來大量新的創(chuàng)意。 

舉一個(gè)例子:

class Counter {
    public int count;

    public void add() {
        count++;
    }
}

public class ThreadDemo1 {
    public static void main(String[] args) {
        Counter counter = new Counter();
        Thread t1 = new Thread(() ->{
            for (int i = 0; i< 50000; i++) {
                counter.add();
            }
        });
        Thread t2 = new Thread(() ->{
            for (int i = 0; i< 50000; i++) {
                counter.add();
            }
        });
        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        System.out.println("count = " + counter.count);
    }
}

這里定義兩個(gè)線程實(shí)例對象t1,t2(執(zhí)行的任務(wù)分別是循環(huán)調(diào)用50000次add操作),add方法的作用是對成員變量count進(jìn)行++,我們設(shè)想兩個(gè)線程并發(fā)執(zhí)行,結(jié)果輸出的count值應(yīng)該為100000,但是并不是,這就是一個(gè)典型的線程安全問題!?。?/p>2.原因

首先我們需要明確add操作主要干了什么?

可以看出 add操作分為了三個(gè)指令,沒進(jìn)行一次++CPU就會執(zhí)行三條指令(其中這三條指令是串行的)

load :把內(nèi)存中的值加載到CPU的寄存器上

add? :在CPU的寄存器上進(jìn)行++操作

save: 把計(jì)算之后的值再存到內(nèi)存當(dāng)中

那為什么會在進(jìn)行add操作的時(shí)候會出現(xiàn)輸出結(jié)果小于100000呢?

我們知道兩個(gè)線程在并發(fā)編程的時(shí)候是搶占式執(zhí)行的(誰先搶到CPU資源誰就會被優(yōu)先調(diào)度,此時(shí)另一個(gè)線程就會阻塞),此時(shí)兩個(gè)線程中的add操作鎖所對應(yīng)的指令就會出現(xiàn)很多種情況,就會造成計(jì)算結(jié)果出錯(cuò)。

這里舉出了兩個(gè)例子,兩個(gè)線程的所對應(yīng)的三條指令順序都不一樣(是因?yàn)榫€程1,2搶占式執(zhí)行當(dāng)某一個(gè)線程執(zhí)行其中一條指令時(shí),另一個(gè)線程被調(diào)度時(shí)會優(yōu)先執(zhí)行另一個(gè)線程的指令,此時(shí)之前的線程就會被阻塞),第一種情況add了兩次正常輸出2,而第二種情況只被add了一次輸出1;

二,線程安全 1.概念

什么是線程安全:線程安全確切的定義十分復(fù)雜,所以我們一般認(rèn)為,如果多線程環(huán)境下代碼運(yùn)行的結(jié)果是符合我們預(yù)期的,即在單線程環(huán)境應(yīng)該的結(jié)果,則說這個(gè)程序是線程安全的;

上述例子若改成單線程:

class Counter2 {
    public int count;

    public void add() {
        count++;
    }
}

public class Test {
    public static void main(String[] args) {
        Counter2 counter2 = new Counter2();
        for (int i = 0; i< 50000; i++) {
            counter2.add();
        }
        for (int i = 0; i< 50000; i++) {
            counter2.add();
        }
        System.out.println("count = " + counter2.count);
    }
}

此時(shí)輸出正確,所以我們可以認(rèn)為上述輸出結(jié)果不是預(yù)期的那種多線程代碼是線程不安全的。

2.原因

1.搶占式執(zhí)行,隨機(jī)調(diào)度(根本原因,由操作系統(tǒng)內(nèi)核決定,無法改變)

2.因?yàn)閱蝹€(gè)進(jìn)程下的多個(gè)線程是資源共享的,所以多個(gè)線程修改同一個(gè)變量時(shí)會線程不安全

?多個(gè)線程修改不同的變量? 沒事

?一個(gè)線程修改同一個(gè)變量? 沒事

?多個(gè)線程讀取同一個(gè)變量? 沒事

3.原子性

?如果修改操作是原子性的,就不會有線程安全問題

?如果修改操作是非原子性的就很大概率出現(xiàn)線程安全問題(上述示例的add操作就是非原子性? ? ? ? ?的,一個(gè)add操作分成了三個(gè)指令去執(zhí)行)

?所以我們?nèi)ケ苊饩€程安全的主要手段就是將非原子性的操作變成原子性---->加鎖

4.內(nèi)存可見性問題

? 當(dāng)一個(gè)線程在讀取數(shù)據(jù),一個(gè)線程在修改數(shù)據(jù)時(shí)就會出現(xiàn)線程安全問題(也就是常說的臟讀問? ? ? ? 題)

5.指令重排序(本質(zhì)上是代碼出現(xiàn)了bug)

三,synchronized關(guān)鍵字

針對線程安全問題,我們往往常用的手段就是把非原子性操作變成原子性操作,此時(shí)就需要用到synchronized關(guān)鍵字(該關(guān)鍵字的作用就是對對象加鎖)

針對上述的代碼進(jìn)行修改:

class Counter {
    public int count;

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

public class ThreadDemo1 {
    public static void main(String[] args) {
        Counter counter = new Counter();
        Thread t1 = new Thread(() ->{
            for (int i = 0; i< 50000; i++) {
                counter.add();
            }
        });
        Thread t2 = new Thread(() ->{
            for (int i = 0; i< 50000; i++) {
                counter.add();
            }
        });
        t1.start();
        t2.start();

        try {
            t1.join();
            t2.join();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }

        System.out.println("count = " + counter.count);
    }
}

此時(shí)輸出結(jié)果為我們預(yù)期的100000;

1.synchronized 的原理

在多線程環(huán)境下,當(dāng)一個(gè)線程在被調(diào)度時(shí)(拿上述例子解釋:當(dāng)線程t1調(diào)用add方法進(jìn)行conut++操作時(shí),因?yàn)榫€程是搶占式執(zhí)行的,此時(shí)線程t2想要調(diào)用add方法時(shí)發(fā)現(xiàn)線程t1正在執(zhí)行add方法,線程t2就會發(fā)生線程阻塞,等待線程t1完全執(zhí)行完時(shí)線程t2才可以進(jìn)行add操作),另一個(gè)線程就會阻塞等待,直到當(dāng)前線程執(zhí)行完畢,另一個(gè)線程才可以執(zhí)行。

當(dāng)有一個(gè)滑稽老鐵在上廁所時(shí)(廁所相當(dāng)于對象,滑稽老鐵相當(dāng)于線程),此時(shí)門就會上鎖(這個(gè)鎖的作用就相當(dāng)于synchronized的作用),其余的滑稽老鐵必須等待當(dāng)前的滑稽老鐵上完廁所,他們才可以使用這個(gè)廁所(相當(dāng)于此時(shí)其他線程是阻塞等待的)。

2.synchronized 的特性

1.互斥

指的是當(dāng)一個(gè)線程執(zhí)行到synchronized對象中時(shí),另一個(gè)對象執(zhí)行到這個(gè)對象時(shí)就會阻塞等待;

進(jìn)入 synchronized 修飾的代碼塊, 相當(dāng)于 加鎖

退出 synchronized 修飾的代碼塊 , 相當(dāng)于 解鎖 2.可重入 synchronized 同步塊對同一條線程來說是可重入的,不會出現(xiàn)自己把自己鎖死的問題;

當(dāng)同一個(gè)線程對一個(gè)對象多次加鎖時(shí),并不會出現(xiàn)問題時(shí)就稱該鎖為可重入,否則就稱該鎖不可重入(此時(shí)會造成死鎖的問題)

3.synchronized的使用案例

synchronized可以修飾方法(包括實(shí)例方法和靜態(tài)方法)也可以修飾代碼塊

修飾實(shí)例方法:鎖的是synchronized對象;

修飾靜態(tài)方法:鎖的是Counter類對象;

修飾代碼塊:鎖的是當(dāng)前對象;

其中的this可以改成任意對象;

4.synchronized總結(jié)?

如果兩個(gè)線程針對同一個(gè)對象進(jìn)行加鎖,就會出現(xiàn)鎖競爭/鎖沖突,一個(gè)線程能夠獲取到鎖(先到先得)另一個(gè)線程阻塞等待,等待到上一個(gè)線程解鎖,它才能獲取鎖成功,否則就不會;

如果兩個(gè)線程針對不同對象加鎖,此時(shí)不會發(fā)生鎖競爭/鎖沖突,這倆線程都能獲取到各自的鎖,不會有阻塞等待了;

兩個(gè)線程,一個(gè)線程加鎖,一個(gè)線程不加鎖這個(gè)時(shí)候就不會有鎖競爭。

四,Java 標(biāo)準(zhǔn)庫中的線程安全類? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ??
線程不安全的集合類線程安全的集合類
ArrayList Vector ( 不推薦使用 )
LinkedList HashTable ( 不推薦使用 )
HashMap ConcurrentHashMap
TreeMapStringBuffer
HashSet
TreeSet
StringBuilder

雖然有的集合類是加鎖了,但是在使用時(shí)并不是建議無腦使用加鎖的集合類,因?yàn)榧渔i也需要很多的時(shí)間開銷(根據(jù)情況進(jìn)行選擇)

還有的雖然沒有加鎖,但是不涉及 "修改",?仍然是線程安全的:String

你是否還在尋找穩(wěn)定的海外服務(wù)器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機(jī)房具備T級流量清洗系統(tǒng)配攻擊溯源,準(zhǔn)確流量調(diào)度確保服務(wù)器高可用性,企業(yè)級服務(wù)器適合批量采購,新人活動首月15元起,快前往官網(wǎng)查看詳情吧


網(wǎng)頁標(biāo)題:線程安全和synchronized關(guān)鍵字-創(chuàng)新互聯(lián)
文章轉(zhuǎn)載:http://weahome.cn/article/djgdid.html

其他資訊

在線咨詢

微信咨詢

電話咨詢

028-86922220(工作日)

18980820575(7×24)

提交需求

返回頂部