Java同步(Synchronization)

来源:https://www.cnblogs.com/lovesong/archive/2018/04/24/8934440.html
-Advertisement-
Play Games

前言 線程間的通信主要通過共用對欄位的訪問和對象引用欄位的引用,可能會產生兩種錯誤,線程干擾和記憶體一致性錯誤。Java的同步就是防止這些錯誤,但當多個線程訪問同一資源會導致線程執行緩慢,甚至暫停執行。 線程干擾(Thread Interference) 例子 class Counter { priv ...


前言

線程間的通信主要通過共用對欄位的訪問和對象引用欄位的引用,可能會產生兩種錯誤,線程干擾和記憶體一致性錯誤。Java的同步就是防止這些錯誤,但當多個線程訪問同一資源會導致線程執行緩慢,甚至暫停執行。

線程干擾(Thread Interference)

例子

class Counter {
    private int c = 0;

    public void increment() {
        c++;
    }

    public void decrement() {
        c--;
    }

    public int value() {
        return c;
    }

}
View Code

如果現在有兩個線程,線程A執行increment,線程B執行decrement,它們都使用了相同的變數c,這時會發生干擾。即便是執行非常簡單的語句,但簡單語句也可以轉化為Java虛擬機的多個步驟,例如c++可以分解為三個步驟:

1、檢索c的當前值。

2、將檢索值加1。

3、將值存儲回c中。

PS:c—也可以分解為相同步驟,只是第二步是減1。

假如線程A和線程B幾乎同時調用,c的初始值為0,則它們交錯的步驟可能是以下順序:

線程A:檢索c。
線程B:檢索c。
線程A:增加檢索值;結果是1。
線程B:減少檢索值;結果是-1。
線程A:將結果存儲在c中; c現在是1。
線程B:將結果存儲在c中; c現在是-1。

線程A的結果丟失了,被線程B覆蓋了。這種交錯只是一種可能性,也可能是B的結果丟失,也可能不會出錯。也就是因為順序是不可預測的,所以線程干擾的錯誤可能難以發現和修複。

記憶體一致性錯誤

不同線程看到的記憶體中的同一份數據卻有不同的“視圖”,原因很複雜,作為程式員最需要做的是處理好“happens-before”的關係,避免問題。

同步方法

Java提供了兩種基本的同步方法:同步方法和同步語句。同步的行為是依賴鎖來構建的,每一個對象都有與之相關的固定鎖,想要獨占訪問對象的線程必須先獲取對象的鎖(拿不到阻塞線程),完成後釋放鎖,同時與請求同一鎖的線程建立一個happens-before關係。

同步方法的作用:

1、當一個線程正在執行一個對象的同步方法時,所有其他調用該對象的同步方法的線程將被阻塞,直到第一個線程執行完成。

2、當一個同步方法退出後,會自動建立與後續調用的同步方法(相同對象)的一個happens-before關係,保證所有線程對對象狀態的修改可見。

註意:

1、在構造函數中使用synchronized關鍵字是語法錯誤。同步構造函數沒有意義,因為只有創建對象的線程在構建時才能訪問它。

2、如果一個對象對多個線程可見,則通過同步方法完成對該對象變數的所有讀取或寫入操作,不然還是會出現線程干擾和記憶體一致性錯誤。

public class SynchronizedCounter {
    private int c = 0;

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

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

    public synchronized int value() {
        return c;
    }
}
View Code

同步語句

另一種創建同步代碼的方法,與同步方法不同,同步語句必須指定提供內部鎖的對象。同步語句有利於通過細粒度同步來提高併發性。

例如,假設類MsLunch具有兩個實例欄位c1和c2,它們從不一起使用(很重要的前提條件!)。這些欄位的所有更新都必須同步,但沒有理由阻止c1的更新與c2的更新交錯,這樣做會創建不必要的阻塞來降低併發性。我們不使用同步方法,而是創建兩個對象來提供鎖。

public class MsLunch {
    private long c1 = 0;
    private long c2 = 0;
    private Object lock1 = new Object();
    private Object lock2 = new Object();

    public void inc1() {
        synchronized(lock1) {
            c1++;
        }
    }

    public void inc2() {
        synchronized(lock2) {
            c2++;
        }
    }
}
View Code

volatile關鍵字

原子操作:一個原子操作,要麼發生,要麼不發生。比如 c=0;(非long和double類型) 這個操作是執行了就會發生。再比如:c++;可分割成三個操作步驟,執行時可能會丟失某些步驟,就不是一個原子操作。非原子操作都會存線上程安全問題,同步方法和同步語句可以讓它變成一個原子操作。

volatile變數是一種稍弱的同步機制,所有聲明為volatile的變數(包括long和double),讀取和寫入都是原子的。

volatile變數特性:

1、當一個線程讀取一個volatile變數時,它看到總是最新的值。

2、原子動作不能交錯,使用volatile變數不用擔心線程干擾。

PS:java.util.concurrent包下提供了一些原子類。

參考文獻

https://docs.oracle.com/javase/tutorial/essential/concurrency/sync.html


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Qone 下一代 Web 查詢語言,使 javascript 支持 LINQ Github: "https://github.com/dntzhang/qone" 緣由 最近剛好修改了騰訊文檔 Excel 表格公式的一些 bug,主要是修改公式的 parser 。比如下麵的腳本怎麼轉成 javasc ...
  • 個人是這麼理解深拷貝和淺拷貝的:就是假設B複製了A,當修改A時,看B是否會發生變化,如果B也跟著變了,說明這是淺拷貝,拿人手短,如果B沒變,那就是深拷貝,自食其力。 一起看看我舉的淺拷貝慄子: 運行結果是:a數組元素跟著b數組改變 在來看看深拷貝的慄子 運行結果:a數組元素未隨b數組改變 ...
  • 圖片上傳 /static/img/H5_addPhoto.png" alt="picture"> /*圖片上傳*/ .photo - box { padding: 10 px; display: inline - block; } ... ...
  • 手把手教你寫網路爬蟲(6) 作者:拓海 摘要:從零開始寫爬蟲,初學者的速成指南! 封面: 下麵是一個超級電腦的排行榜,如果我們能擁有其中任意一個,那麼我們就不需要搞什麼分散式系統。可是我們買不起,即使買得起,也交不起電費,所以我們只好費腦子搞分散式。 Rank System Cores Rmax ...
  • 一、文件的打開與關閉 1. 文件的打開 在python,使用open函數,可以打開一個已經存在的文件,或者創建一個新文件。 示例如下: f = open('test.txt', 'w') 2. 文件的關閉 示例如下: 註意:文件打開,執行必要的操作後必須要關閉。 但是我們總是經常忘記關閉它,怎麼辦呢 ...
  • 之前的文章中,分別從APS,排產到規劃引擎敘述了一些理論基礎;並介紹了一些Optaplanner大概的情況;並一步步將Optaplanner的示例運行起來,將示例源碼導進Eclipse分析了一下它的Hello world入門示例,從本篇開始,我們將分步學習它的一些概念及用法。 什麼是Optaplan ...
  • java中的一些概念彙總 什麼是Java虛擬機?為什麼Java被稱作是“平臺無關的編程語言”? Java虛擬機是一個可以執行Java位元組碼的虛擬機進程。Java源文件被編譯成能被Java虛 擬機執行的位元組碼文件。 Java被設計成允許應用程式可以運行在任意的平臺,而不需要程式員為每一個平臺單獨重 寫 ...
  • <! more 關註我 轉載請務必註明原創地址為: "http://www.54tianzhisheng.cn/2018/04/15/springboot2_code/" 項目結構 結構分析: + Spring boot project 核心代碼,代碼量很多(197508 行) + Spring b ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...