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

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程语言 > java >内容正文

java

Java 多线程三大核心

發布時間:2025/3/21 java 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java 多线程三大核心 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

原子性

Java?的原子性就和數據庫事務的原子性差不多,一個操作中要么全部執行成功或者失敗。

JMM?只是保證了基本的原子性,但類似于?i++?之類的操作,看似是原子操作,其實里面涉及到:

  • 獲取 i 的值。
  • 自增。
  • 再賦值給 i。

這三步操作,所以想要實現?i++?這樣的原子操作就需要用到?synchronized?或者是?lock?進行加鎖處理。

如果是基礎類的自增操作可以使用?AtomicInteger?這樣的原子類來實現(其本質是利用了?CPU?級別的 的?CAS?指令來完成的)。

其中用的最多的方法就是:?incrementAndGet()?以原子的方式自增。 源碼如下:

public final long incrementAndGet() {for (;;) {long current = get();long next = current + 1;if (compareAndSet(current, next))return next;}}

首先是獲得當前的值,然后自增 +1。接著則是最核心的?compareAndSet()?來進行原子更新。

public final boolean compareAndSet(long expect, long update) {return unsafe.compareAndSwapLong(this, valueOffset, expect, update);}

其邏輯就是判斷當前的值是否被更新過,是否等于?current,如果等于就說明沒有更新過然后將當前的值更新為?next,如果不等于則返回false?進入循環,直到更新成功為止。

還有其中的?get()?方法也很關鍵,返回的是當前的值,當前值用了?volatile?關鍵詞修飾,保證了內存可見性。

private volatile int value;

可見性

現代計算機中,由于?CPU?直接從主內存中讀取數據的效率不高,所以都會對應的?CPU?高速緩存,先將主內存中的數據讀取到緩存中,線程修改數據之后首先更新到緩存,之后才會更新到主內存。如果此時還沒有將數據更新到主內存其他的線程此時來讀取就是修改之前的數據。

如上圖所示。

volatile?關鍵字就是用于保證內存可見性,當線程A更新了 volatile 修飾的變量時,它會立即刷新到主線程,并且將其余緩存中該變量的值清空,導致其余線程只能去主內存讀取最新值。

使用?volatile?關鍵詞修飾的變量每次讀取都會得到最新的數據,不管哪個線程對這個變量的修改都會立即刷新到主內存。

synchronized和加鎖也能能保證可見性,實現原理就是在釋放鎖之前其余線程是訪問不到這個共享變量的。但是和?volatile相比開銷較大。

順序性

以下這段代碼:

int a = 100 ; //1 int b = 200 ; //2 int c = a + b ; //3

正常情況下的執行順序應該是?1>>2>>3。但是有時?JVM?為了提高整體的效率會進行指令重排導致執行的順序可能是?2>>1>>3。但是?JVM?也不能是什么都進行重排,是在保證最終結果和代碼順序執行結果一致的情況下才可能進行重排。

重排在單線程中不會出現問題,但在多線程中會出現數據不一致的問題。

Java 中可以使用?volatile?來保證順序性,synchronized 和 lock?也可以來保證有序性,和保證原子性的方式一樣,通過同一段時間只能一個線程訪問來實現的。

除了通過?volatile?關鍵字顯式的保證順序之外,?JVM?還通過?happen-before?原則來隱式的保證順序性。

其中有一條就是適用于?volatile?關鍵字的,針對于?volatile?關鍵字的寫操作肯定是在讀操作之前,也就是說讀取的值肯定是最新的。

volatile 的應用

雙重檢查鎖的單例模式

可以用?volatile?實現一個雙重檢查鎖的單例模式:

public class Singleton {private static volatile Singleton singleton;private Singleton() {}public static Singleton getInstance() {if (singleton == null) {synchronized (Singleton.class) {if (singleton == null) {singleton = new Singleton();}}}return singleton;}}

這里的?volatile?關鍵字主要是為了防止指令重排。 如果不用?volatile?,singleton = new Singleton();,這段代碼其實是分為三步:

  • 分配內存空間。(1)
  • 初始化對象。(2)
  • 將?singleton?對象指向分配的內存地址。(3)

加上?volatile?是為了讓以上的三步操作順序執行,反之有可能第三步在第二步之前被執行就有可能導致某個線程拿到的單例對象還沒有初始化,以致于使用報錯。

控制停止線程的標記

private volatile boolean flag ;private void run(){new Thread(new Runnable() {@Overridepublic void run() {doSomeThing();}});}private void stop(){flag = false ;}

這里如果沒有用 volatile 來修飾 flag ,就有可能其中一個線程調用了?stop()方法修改了 flag 的值并不會立即刷新到主內存中,導致這個循環并不會立即停止。

這里主要利用的是?volatile?的內存可見性。

總結一下:

  • volatile?關鍵字只能保證可見性,順序性,不能保證原子性

總結

以上是生活随笔為你收集整理的Java 多线程三大核心的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。