日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

Java核心知识体系8:Java如何保证线程安全性

發(fā)布時間:2023/12/24 java 48 coder
生活随笔 收集整理的這篇文章主要介紹了 Java核心知识体系8:Java如何保证线程安全性 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

Java核心知識體系1:泛型機(jī)制詳解
Java核心知識體系2:注解機(jī)制詳解
Java核心知識體系3:異常機(jī)制詳解
Java核心知識體系4:AOP原理和切面應(yīng)用
Java核心知識體系5:反射機(jī)制詳解
Java核心知識體系6:集合框架詳解
Java核心知識體系7:線程不安全分析

1 Java內(nèi)存模型(JMM) 如何解決并發(fā)問題

維度1:使用關(guān)鍵字、屬性進(jìn)行優(yōu)化
JMM本質(zhì)實(shí)際就是:Java 內(nèi)存模型規(guī)范了 JVM 如何提供按需禁用緩存和編譯優(yōu)化的方法。這些方法包括了:

  • volatile、synchronized 和 final 關(guān)鍵字
  • Happens-Before 規(guī)則

維度2:從 順序一致性、可見性、有序性、原子性角度

  • 順序一致性

一個線程中的所有操作按照程序的順序執(zhí)行,不受其他線程的影響。

  • 原子性

Java程序中,對數(shù)據(jù)的讀和寫操作是原子性操作,即這些操作是不可被中斷的,要么執(zhí)行,要么不執(zhí)行,否則會產(chǎn)生問題。
通過下面的案例可以看出,哪些是原子操作,哪些是非原子操作:

// 1個動作,線程直接將值賦給idx,也就是直接寫到內(nèi)存中
idx = 100

// 3個動作:先定義 jdx,再讀取idx的值,最后賦值給jdx
jdx := idx

// 3個動作:讀取jdx的值,進(jìn)行加1操作,然后新值重新寫入新的值
jdx ++

從上面的案例中可以看中,只有第一個例子才是具備原子性的,因?yàn)樗挥幸粋€存的動作。至于其他的例子,包含讀取、操作、賦值等多個動作,有一個動作失敗則不成立。
所以,基本讀取和賦值,Java內(nèi)存模型可以保證原子性操作,如果要實(shí)現(xiàn)更大范圍、步驟更多的操作的原子性,則需要通過synchronized或者Lock來實(shí)現(xiàn)。
synchronized和Lock的存在是為了夠保證任一時刻只有一個線程能夠執(zhí)行該代碼塊,這樣也就解決了原子性。

  • 可見性

Java提供了volatile關(guān)鍵字來保證可見性,使用volatile來修飾共享變量,可以保證修改的值立即更新到主存中。這樣其他線程讀取數(shù)據(jù)時,始終都會從內(nèi)存中讀取到新值。
而普通的共享變量不能保證可見性,因?yàn)樾薷闹?,不確定什么時候被寫入主存,當(dāng)其他Thread去讀取時,內(nèi)存中很有可能還是原來的舊值,所以無法保證可見性。
另外,通過synchronized關(guān)鍵字和Lock功能也能夠保證可見性,因?yàn)槟芟拗仆粫r刻只有一個線程獲取鎖然后執(zhí)行同步代碼,且在釋放之前會將變量的修改更新到主存中。所以實(shí)時可見。

  • 有序性

在Java里面,可以通過volatile關(guān)鍵字來保證一定的“有序性”。
另外,通過synchronized關(guān)鍵字和Lock功能也能夠保證可見性,因?yàn)槟芟拗仆粫r刻只有一個線程獲取鎖然后執(zhí)行同步代碼,相當(dāng)于是讓線程順序執(zhí)行同步代碼,自然就保證了有序性。
注:JMM是通過Happens-Before 規(guī)則來保證Thread操作有序性。

2.1 關(guān)鍵字: volatile、synchronized 和 final

在Java中,volatile、synchronized和final是三個非常重要的關(guān)鍵字,它們都與并發(fā)編程密切相關(guān)。下面是對這三個關(guān)鍵字的詳細(xì)介紹:

2.1.1 volatile

volatile是Java中的一種修飾符,它用于聲明一個共享變量,以確保多個線程對該變量的訪問是可見的和有序的。volatile關(guān)鍵字的作用是禁止指令重排和強(qiáng)制刷新緩存,以保證操作的順序性和可見性。
當(dāng)一個變量被聲明為volatile時,它表示該變量的值可能會被意想不到地改變。編譯器和處理器會注意到這個變量的特殊性,并采取相應(yīng)的措施來保證多個線程對該變量的訪問是正確的。具體來說,volatile關(guān)鍵字會禁止編譯器對volatile變量進(jìn)行優(yōu)化,每次讀取該變量時都會直接從它的內(nèi)存地址中讀取,而不是從寄存器或緩存中讀取。同時,volatile關(guān)鍵字也會強(qiáng)制處理器在每個操作該變量的指令之后立即刷新緩存,以保證其他線程能夠看到最新的值。
需要注意的是,雖然volatile關(guān)鍵字可以保證可見性和有序性,但它并不能保證原子性。也就是說,如果一個操作包含多個步驟,而這些步驟不能被一個指令替換,那么這個操作就不能被保證為原子性。在這種情況下,需要使用鎖或者其他同步機(jī)制來保證原子性。

2.1.2 synchronized

synchronized是Java中的一種關(guān)鍵字,它用于實(shí)現(xiàn)同步代碼塊和方法。synchronized關(guān)鍵字可以保證同一時刻只有一個線程能夠執(zhí)行被synchronized修飾的代碼塊或方法。synchronized關(guān)鍵字會創(chuàng)建一個鎖對象或鎖標(biāo)識符,當(dāng)一個線程獲取了這個鎖對象或鎖標(biāo)識符后,其他線程就不能再獲取這個鎖對象或鎖標(biāo)識符,直到第一個線程釋放了這個鎖對象或鎖標(biāo)識符。
synchronized關(guān)鍵字可以保證多個線程對共享變量的訪問是互斥的,也就是說在同一時刻只有一個線程能夠訪問共享變量。這樣可以避免多個線程同時修改共享變量而導(dǎo)致數(shù)據(jù)不一致的問題。同時,synchronized關(guān)鍵字還可以保證多個線程之間的操作是有序的,即一個線程在執(zhí)行synchronized代碼塊或方法之前必須等待其他線程完成之前的操作。
需要注意的是,synchronized關(guān)鍵字雖然可以保證互斥性和有序性,但它并不能保證原子性。也就是說,如果一個操作包含多個步驟,而這些步驟不能被一個指令替換,那么這個操作就不能被保證為原子性。在這種情況下,需要使用其他同步機(jī)制來保證原子性。

2.1.3 final

final是Java中的一種修飾符,它用于聲明一個最終變量或方法。final關(guān)鍵字表示該變量或方法不能被修改或重寫。具體來說,final關(guān)鍵字可以用于聲明一個常量,該常量的值不能被修改;也可以用于聲明一個方法,該方法不能被重寫。
final關(guān)鍵字在并發(fā)編程中也有著重要的作用。final關(guān)鍵字可以保證一個共享變量的值只被一個線程修改,這樣可以避免多個線程同時修改共享變量而導(dǎo)致數(shù)據(jù)不一致的問題。同時,final關(guān)鍵字還可以保證一個方法的執(zhí)行不會被其他線程中斷或干擾,這樣可以保證方法的原子性和可見性。
需要注意的是,final關(guān)鍵字并不能保證多個線程之間的操作是有序的。也就是說,在一個線程中執(zhí)行final方法時,其他線程可能會同時執(zhí)行自己的操作,而這些操作之間是沒有順序關(guān)系的。在這種情況下,需要使用其他同步機(jī)制來保證操作的順序性。

2.2 Happens-Before 規(guī)則

上面提到了可以用 volatile 和 synchronized 來保證有序性。除此之外,在JVM 中還有Happens-Before規(guī)則,用來確定并發(fā)操作之間的順序關(guān)系。
Happens-Before規(guī)則定義了以下幾種順序關(guān)系:

2.2.1 程序順序規(guī)則(Program Order Rule)

在一個程序中,按照代碼的順序,先執(zhí)行的操作Happens-Before后執(zhí)行的操作。這意味著在程序中,如果一個操作先于另一個操作執(zhí)行,那么這個操作的結(jié)果對后續(xù)操作是可見的。

2.2.2 管程鎖定規(guī)則(Monitor Lock Rule)

一個unlock操作先行發(fā)生于后面對同一個鎖的lock操作。

2.2.3 volatile變量規(guī)則(Volatile Variable Rule)

對一個 volatile 變量的寫操作先行發(fā)生于后面對這個變量的讀操作,先寫后讀。

2.2.4 線程啟動規(guī)則(Thread Start Rule)

Thread 對象的 start() 方法調(diào)用先行發(fā)生于此線程的每一個動作。

2.2.5 線程加入規(guī)則((Thread Join Rule)

Thread 對象的結(jié)束先行發(fā)生于 join() 方法返回。

2.2.6 線程終止規(guī)則(Thread Termination Rule)

線程中的所有操作都先行發(fā)生于對此線程的終止檢測,我們可以通過Thread.join()方法和Thread.isAlive()的返回值等手段檢測線程是否已經(jīng)終止執(zhí)行

2.2.7 線程中斷規(guī)則( Thread Interruption Rule)

對線程 interrupt() 方法的調(diào)用先行發(fā)生于被中斷線程的代碼檢測到中斷事件的發(fā)生,可以通過 interrupted() 方法檢測到是否有中斷發(fā)生。

2.2.8 對象終結(jié)規(guī)則(Finalizer Rule)

一個對象的初始化完成(構(gòu)造函數(shù)執(zhí)行結(jié)束)先行發(fā)生于它的 finalize() 方法的開始。

2.2.9 傳遞性(Transitivity)

如果操作A先行發(fā)生于操作B,操作B先行發(fā)生于操作C,那就可以得出操作A先行發(fā)生于操作C的結(jié)論。

3 線程安全性能討論

在多線程環(huán)境中,一個類或者一個函數(shù)不管在何種運(yùn)行時環(huán)境或交替執(zhí)行方式,都能保證正確的行為,被安全的調(diào)用,就說明線程是安全的。
這個“正確的行為”通常包括原子性、可見性和有序性。
但是線程安全不是非真即假,共享數(shù)據(jù)按照安全程度的強(qiáng)弱順序可以分成以下五類:

  • 不可變
  • 絕對線程安全
  • 相對線程安全
  • 線程兼容
  • 線程對立

按照線程安全性的強(qiáng)弱順序,不可變 > 絕對線程安全 > 相對線程安全 > 線程兼容 > 線程對立。

3.1 不可變(Immutable)

不可變的對象在創(chuàng)建后其狀態(tài)就不能被修改,因此它們自然是線程安全的。任何線程在任何時候訪問這些對象,都會看到相同的數(shù)據(jù)。
多線程環(huán)境下,應(yīng)當(dāng)盡量使對象成為不可變,來滿足線程安全。
不可變的類型包括:

  • final 關(guān)鍵字修飾的基本數(shù)據(jù)類型
  • String
  • 枚舉類型
  • Number 部分子類,如 Long 和 Double 等數(shù)值包裝類型,BigInteger 和 BigDecimal 等大數(shù)據(jù)類型。但同為 Number 的原子類 AtomicInteger 和 AtomicLong 則是可變的

對于集合類型,可以使用 Collections.unmodifiableXXX() 方法來獲取一個不可變的集合。

XXX 可以是Map、List、Set

public class ImmutableClass {
    public static void main(String[] args) {
        Map<String, Integer> testMap = new HashMap<>();
        Map<String, Integer> testUnmodifiable = Collections.unmodifiableMap(testMap);
        testUnmodifiable.put("input-a", 1);
    }
}

執(zhí)行時拋出異常

Exception in thread "main" java.lang.UnsupportedOperationException
    at java.util.Collections$testUnmodifiable.put(Collections.java:1523)
    at ImmutableExample.main(ImmutableClass.java:9)

不可變狀態(tài)還可以這么理解,外部無法對數(shù)據(jù)狀態(tài)進(jìn)行修改,比如

public class ImmutableClass {  
    private final int value;  
  
    public ImmutableClass(int value) {  
        this.value = value;  
    }  
  
    public int getValue() {  
        return value;  
    }  
}

在這個例子中,ImmutableClass是不可變的,因?yàn)樗臉?gòu)造函數(shù)是私有的,外部無法修改其狀態(tài)。因此,多個線程同時訪問和獲取ImmutableClass對象的值時,不會出現(xiàn)數(shù)據(jù)不一致的問題。

3.2 絕對線程安全(Absolute Thread Safety)

絕對線程安全的對象無論運(yùn)行時環(huán)境如何,調(diào)用者都不需要任何額外的同步措施。這通常需要付出較大的代價來實(shí)現(xiàn)。

public class ThreadSafeClass {  
    private int value;  
  
    public synchronized void setValue(int value) {  
        this.value = value;  
    }  
  
    public synchronized int getValue() {  
        return value;  
    }  
}

在這個例子中,ThreadSafeClass的每個方法都使用了synchronized關(guān)鍵字進(jìn)行同步。這保證了無論多少個線程同時訪問ThreadSafeClass的對象,每個線程的操作都會被串行執(zhí)行,不會出現(xiàn)數(shù)據(jù)競爭的問題。

3.3 相對線程安全(Relative Thread Safety)

相對線程安全的對象需要保證單個操作是線程安全的,在調(diào)用的時候不需要做額外的保障措施。但在連續(xù)調(diào)用時可能需要額外的同步措施來保證調(diào)用的正確性。
Java 語言中,大部分的線程安全類都屬于這種類型,例如 Vector、HashTable、Collections 的 synchronizedCollection() 方法包裝的集合等。
以Hashtable為例,因?yàn)樗拿總€方法都是同步的。但是,如果多個線程連續(xù)調(diào)用Hashtable的不同方法(如put和get),仍然可能出現(xiàn)競態(tài)條件。為了避免這種情況,調(diào)用者需要在外部進(jìn)行額外的同步。

在下面代碼中,如果Vector中的一個元素被線程A刪除,而線程B試圖獲取一個已經(jīng)被刪除的元素,那么就會拋出 ArrayIndexOutOfBoundsException。

public class VectorUnsafeExample {
    private static Vector<Integer> vector = new Vector<>();

    public static void main(String[] args) {
        while (true) {
            for (int i = 0; i < 100; i++) {
                vector.add(i);
            }
            ExecutorService executorService = Executors.newCachedThreadPool();
            executorService.execute(() -> {
                for (int i = 0; i < vector.size(); i++) {
                    vector.remove(i);
                }
            });
            executorService.execute(() -> {
                for (int i = 0; i < vector.size(); i++) {
                    vector.get(i);
                }
            });
            executorService.shutdown();
        }
    }
}
Exception in thread "Thread-159738" java.lang.ArrayIndexOutOfBoundsException: Array index out of range: 3
    at java.util.Vector.remove(Vector.java:831)
    at VectorUnsafeExample.lambda$main$0(VectorUnsafeExample.java:14)
    at VectorUnsafeExample$$Lambda$1/713338599.run(Unknown Source)
    at java.lang.Thread.run(Thread.java:745)

如果要保證上面的代碼能正確執(zhí)行下去,就需要對刪除元素和獲取元素的代碼進(jìn)行同步。

# 獨(dú)立線程A執(zhí)行刪除操作
executorService.execute(() -> {
    synchronized (vector) {
        for (int i = 0; i < vector.size(); i++) {
            vector.remove(i);
        }
    }
});
# 獨(dú)立線程B執(zhí)行讀取操作
executorService.execute(() -> {
    synchronized (vector) {
        for (int i = 0; i < vector.size(); i++) {
            vector.get(i);
        }
    }
});

3.4 線程兼容(Thread Compatibility)

線程兼容的對象本身不是線程安全的,但可以通過在調(diào)用端添加額外的同步措施來保證在多線程環(huán)境下的安全使用。
Java API 中大部分的類都是屬于線程兼容的,比如ArrayList類就不是線程安全的。如果多個線程同時修改ArrayList,可能會導(dǎo)致數(shù)據(jù)不一致。但是,如果調(diào)用者在修改ArrayList時使用synchronized塊或其他同步機(jī)制進(jìn)行同步,就可以保證線程安全。

public class ThreadCompatibleClass {  
    private int value;  
  
    public void setValue(int value) {  
        this.value = value;  
    }  
  
    public int getValue() {  
        return value;  
    }  
}

在這個例子中,ThreadCompatibleClass的方法沒有使用synchronized關(guān)鍵字進(jìn)行同步。因此,如果多個線程同時修改ThreadCompatibleClass的對象,可能會導(dǎo)致數(shù)據(jù)不一致。

3.5 線程對立(Thread Hostility)

線程對立的對象無論如何都無法在多線程環(huán)境下并發(fā)使用,即使采取了同步措施。
一個典型的例子是Java中的ThreadLocalRandom類。這個類用于生成隨機(jī)數(shù),并且每個線程都有其自己的隨機(jī)數(shù)生成器實(shí)例。由于每個線程使用不同的實(shí)例,因此無需擔(dān)心線程安全問題。但是,如果嘗試在沒有正確初始化ThreadLocalRandom的情況下跨線程使用它,就可能導(dǎo)致問題。
這種情況下,即使添加了同步措施也無法保證線程安全。

4 如何實(shí)現(xiàn)線程安全

4.1 synchronized關(guān)鍵字/ReentrantLock特性

  • synchronized關(guān)鍵字

在Java中,synchronized關(guān)鍵字是一種內(nèi)置的同步機(jī)制,用于控制多個線程對共享資源的訪問。它用于在并發(fā)環(huán)境中保護(hù)代碼塊,確保同一時刻只有一個線程可以執(zhí)行該代碼塊。
synchronized關(guān)鍵字可以應(yīng)用于方法或代碼塊。當(dāng)它應(yīng)用于方法時,它將鎖住該方法的對象。當(dāng)它應(yīng)用于代碼塊時,它將鎖住指定的鎖對象。

public class SynchronizedExample {  
    private int count = 0;  
  
    public synchronized void incrementCount() {  
        count++;  
    }  
}

上面這個例子中,incrementCount()方法使用了synchronized關(guān)鍵字。這意味著在任何時刻,只有一個線程可以執(zhí)行該方法。如果有其他線程試圖同時執(zhí)行該方法,它們將會被阻塞,直到當(dāng)前線程完成該方法的執(zhí)行。

  • ReentrantLock特性

ReentrantLock 是 Java 中的一個可重入鎖,它是一種比 synchronized 關(guān)鍵字更靈活的線程同步機(jī)制。ReentrantLock 允許一個線程多次獲取同一個鎖,而不會產(chǎn)生死鎖。它也支持公平鎖和非公平鎖,可以根據(jù)實(shí)際需求進(jìn)行選擇。
下面是一個使用 ReentrantLock 的示例:

import java.util.concurrent.locks.ReentrantLock;  
  
public class ReentrantLockExample {  
    private final ReentrantLock lock = new ReentrantLock();  
    private int count = 0;  
  
    public void incrementCount() {  
        lock.lock();  
        try {  
            count++;  
        } finally {  
            lock.unlock();  
        }  
    }  
  
    public int getCount() {  
        return count;  
    }  
}

在上面的這個例子中,我們定義了一個 ReentrantLock 和一個計數(shù)器 count。
incrementCount() 方法使用 lock.lock() 獲取鎖,然后增加計數(shù)器的值,最后使用 lock.unlock() 釋放鎖。
getCount() 方法直接返回計數(shù)器的值,無需獲取鎖。
這種方式比使用 synchronized 關(guān)鍵字更靈活,因?yàn)樗梢约?xì)粒度地控制需要同步的代碼塊,而不是整個方法。

★ 后續(xù)的章節(jié)會詳細(xì)的介紹 synchronized關(guān)鍵字和ReentrantLock特性,敬請期待

4.2 非阻塞同步

在JAVA中,互斥同步最主要的問題就是線程阻塞和喚醒所帶來的開銷導(dǎo)致的性能問題,這種同步也稱為阻塞同步,是一種悲觀的并發(fā)策略,無論共享數(shù)據(jù)是否真的會出現(xiàn)競爭,它都要進(jìn)行加鎖,
這樣 用戶態(tài)核心態(tài)轉(zhuǎn)換、維護(hù)鎖計數(shù)器和阻塞檢查、線程喚醒等操作都會產(chǎn)生大量的開銷。
非阻塞同步是指在多線程環(huán)境下,不需要使用阻塞等待的方式來實(shí)現(xiàn)同步控制,線程可以一直進(jìn)行計算操作,而不會被阻塞。下面介紹幾種手段實(shí)現(xiàn)非阻塞同步。

  1. CAS
    隨著硬件指令集水平的發(fā)展,我們經(jīng)常使用基于沖突檢測的樂觀并發(fā)策略: 先執(zhí)行操作,如果沒有其它線程爭用共享數(shù)據(jù),那操作就成功了,否則采取補(bǔ)償措施(始終重試,直至成功)。這種樂觀的并發(fā)策略的許多實(shí)現(xiàn)都不需要將線程阻塞,因此這種同步操作稱為非阻塞同步。
    樂觀鎖需要操作和沖突檢測這兩個步驟具備原子性,這里就不能再使用互斥同步來保證了,只能靠硬件來完成。硬件支持的原子性操作最典型的是: 比較并交換(Compare-and-Swap,CAS)。
    CAS操作包含三個操作數(shù) —— 內(nèi)存位置(V)、預(yù)期原值(A)和新值(B)。如果內(nèi)存位置V的值與預(yù)期原值A(chǔ)相匹配,則將內(nèi)存位置的值更新為B,否則不進(jìn)行任何操作。在并發(fā)環(huán)境中,CAS操作可以保證數(shù)據(jù)的一致性和線程安全性。

  2. AtomicInteger

AtomicInteger是Java中的一個原子整數(shù)類,它提供了原子操作的更新方法,可以在多線程環(huán)境下安全地更新共享的整數(shù)變量。
AtomicInteger的更新方法包括incrementAndGet()、getAndIncrement()、decrementAndGet()、getAndDecrement()、compareAndSet()等,它們使用了 Unsafe 類的 CAS 操作,保證對共享變量的操作是原子性的。

以下代碼使用了 AtomicInteger 執(zhí)行了計數(shù)操作。

import java.util.concurrent.atomic.AtomicInteger;  
  
public class AtomicIntegerExample {  
    private static AtomicInteger counter = new AtomicInteger(0);  
  
    public static void main(String[] args) {  
        // 啟動10個線程,每個線程將計數(shù)器加10  
        for (int i = 0; i < 10; i++) {  
            new Thread(() -> {  
                for (int j = 0; j < 10; j++) {  
                    counter.incrementAndGet();  
                }  
            }).start();  
        }  
  
        // 等待所有線程執(zhí)行完畢  
        try {  
            Thread.sleep(1000);  
        } catch (InterruptedException e) {  
            e.printStackTrace();  
        }  
  
        // 輸出計數(shù)器的值  
        System.out.println("Counter: " + counter);  
    }  
}

在這個示例中,我們使用AtomicInteger來維護(hù)一個計數(shù)器的值,并啟動了10個線程,每個線程將計數(shù)器加10次。由于AtomicInteger提供了原子操作的更新方法,因此即使多個線程同時更新計數(shù)器的值,也不會出現(xiàn)線程安全問題。最后,我們輸出計數(shù)器的值,可以看到它應(yīng)該是100(10個線程每個線程執(zhí)行10次計數(shù)器加1操作)。

  1. ABA
    如果某個線程將變量A更改為B后再更改為A,那么另一個等待CAS操作的線程會認(rèn)為該變量沒有發(fā)生過改變,仍然是A,然后執(zhí)行CAS操作。這樣就可能導(dǎo)致數(shù)據(jù)的不一致。
    J.U.C 包提供了一個帶有標(biāo)記的原子引用類 AtomicStampedReference 來解決這個問題,它可以通過控制變量值的版本來保證 CAS 的正確性。大部分情況下 ABA 問題不會影響程序并發(fā)的正確性,如果需要解決 ABA 問題,改用傳統(tǒng)的互斥同步可能會比原子類更高效。
    另外,Java 8引入了一種新的原子類:LongAdder和LongAccumulator,它們內(nèi)部采用了分段化的思想來解決高并發(fā)下的ABA問題。它們將內(nèi)部變量分為一個數(shù)組,每個線程更新自己的分段,最后再合并結(jié)果。這種方式既解決了ABA問題,又提高了并發(fā)性能。

4.3 無同步方案

換一個思路,如果沒有方法的計算不涉及共享數(shù)據(jù),不需要進(jìn)行同步,是不是就不需要任何同步措施去保證正確性,也就沒有線程安全的問題。

  • 棧封閉:多個線程訪問同一個方法的局部變量時,不會出現(xiàn)線程安全問題,因?yàn)榫植孔兞看鎯υ谔摂M機(jī)棧中,屬于線程私有的。
  • 線程本地存儲(Thread Local Storage):如果一段代碼中所需要的數(shù)據(jù)必須與其他代碼共享,那就看看這些共享數(shù)據(jù)的代碼是否能保證在同一個線程中執(zhí)行。如果能保證,我們就可以把共享數(shù)據(jù)的可見范圍限制在同一個線程之內(nèi),這樣,無須同步也能保證線程之間不出現(xiàn)數(shù)據(jù)爭用的問題。
  • 可重入代碼(Reentrant Code):可以在代碼執(zhí)行的任何時刻中斷它,轉(zhuǎn)而去執(zhí)行另外一段代碼(包括遞歸調(diào)用它本身),而在控制權(quán)返回后,原來的程序不會出現(xiàn)任何錯誤。

這塊簡單介紹,后續(xù)會有專門的章節(jié)進(jìn)行學(xué)習(xí)

5 總結(jié)

  • 了解了多線程產(chǎn)生的原因,以及線程不安全的原因
  • 從 可見性,原子性和有序性 來闡述并發(fā)狀態(tài)下線程不安全的原因
  • 分析了Java是怎么解決并發(fā)問題的

總結(jié)

以上是生活随笔為你收集整理的Java核心知识体系8:Java如何保证线程安全性的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯,歡迎將生活随笔推薦給好友。

主站蜘蛛池模板: 蜜桃精品在线 | 国产福利午夜 | 久久久久国产精品一区 | 日韩av在线影院 | 欧美一级在线免费观看 | 天天射天天色天天干 | 伊人网在线视频 | av午夜在线 | 老司机在线永久免费观看 | 日韩欧美国产亚洲 | 光明影院手机版在线观看免费 | 欧美69囗交视频 | 国产精品人八做人人女人a级刘 | 国产高清第一页 | 午夜亚洲福利在线老司机 | 男人日女人b视频 | 日日夜夜国产精品 | 精品日本一区二区三区在线观看 | 日本韩国欧美一区二区 | 视频在线免费观看 | 欧美人与禽zozzo禽性配 | 日韩在线观看视频一区 | 熟妇高潮一区二区三区在线播放 | 天天干影院 | 午夜青青草 | 久热最新视频 | 日本亚洲一区 | 色视频在线免费观看 | 一本色道久久88加勒比—综合 | 少妇高潮av | 成人动漫h在线观看 | 青青av| 一级黄色大片视频 | 91精品国产入口在线 | 国产女主播一区二区三区 | 亚洲av成人无码一二三在线观看 | 亚洲精品九九 | 日韩精品成人一区二区在线 | 国产伦精品一区三区精东 | www.一区二区三区 | 超碰人体| www久久99| 成人黄色片视频 | 偷拍青青草 | 丰满人妻一区二区三区在线 | 白白色2012年最新视频 | 国产精品麻豆一区 | 精品国产乱码久久久久久108 | 国产成人二区 | 性高潮久久久久久久 | 少妇丰满尤物大尺度写真 | 草草影院av | 奇米影视四色777 | 精品免费一区二区 | 久草欧美视频 | 欧美精品一区二区三区视频 | 日日夜夜噜 | 欧美草逼网 | 5d肉蒲团之性战奶水 | 欧美天天性 | 99国产精品免费视频 | 亚洲无圣光 | 成人av动漫在线 | 久久无吗视频 | 制服丝袜在线播放 | 日本一本不卡 | 亚洲一区二区视频网站 | 少妇一级视频 | 亚洲成网站 | aaa黄色片| 日韩午夜| 男生和女生一起差差差视频 | 一个人看的毛片 | 午夜久久久久久久久久影院 | 久久久久久久网 | 免费观看一区二区三区视频 | 免费日韩欧美 | 公侵犯一区二区三区 | 日本羞羞网站 | 操人视频免费看 | 中文字幕无线码 | 免费在线观看毛片 | 国内偷拍久久 | 亚洲一区二区日韩欧美 | 国产真实乱在线更新 | 综合激情网五月 | 精品无码m3u8在线观看 | www.国产毛片 | 日韩三级在线播放 | a天堂在线| 精品久久国产视频 | 亚洲国产精品午夜久久久 | 国产精品久久久久久久av | 天堂在线视频观看 | 北京富婆泄欲对白 | 一边摸上面一边摸下面 | 欧美激情校园春色 | www.伊人.com | 久久免费黄色 |