Java 鎖機制 synchronized

来源:http://www.cnblogs.com/zhaoyanjun/archive/2017/07/17/7197416.html
-Advertisement-
Play Games

轉載請標明出處:http://blog.csdn.net/zhaoyanjun6/article/details/75126630 本文出自 "【趙彥軍的博客】" 1、前言 在多線程併發編程中Synchronized一直是元老級角色,很多人都會稱呼它為重量級鎖,但是隨著Java SE1.6對Sync ...


轉載請標明出處:http://blog.csdn.net/zhaoyanjun6/article/details/75126630
本文出自【趙彥軍的博客】

1、前言

在多線程併發編程中Synchronized一直是元老級角色,很多人都會稱呼它為重量級鎖,但是隨著Java SE1.6對Synchronized進行了各種優化之後,有些情況下它並不那麼重了,本文詳細介紹了Java SE1.6中為了減少獲得鎖和釋放鎖帶來的性能消耗而引入的偏向鎖和輕量級鎖,以及鎖的存儲結構和升級過程。

2、同步的基礎

java中的每一個對象都可以作為鎖。

對於同步方法,鎖是當前實例對象。
對於靜態同步方法,鎖是當前對象的Class對象。
對於同步方法塊,鎖是Synchonized括弧里配置的對象。
當一個線程試圖訪問同步代碼塊時,它首先必須得到鎖,退出或拋出異常時必須釋放鎖。那麼鎖存在哪裡呢?鎖裡面會存儲什麼信息呢?

3、同步的原理

JVM規範規定JVM基於進入和退出Monitor對象來實現方法同步和代碼塊同步,但兩者的實現細節不一樣。代碼塊同步是使用monitorenter和monitorexit指令實現,而方法同步是使用另外一種方式實現的,細節在JVM規範里並沒有詳細說明,但是方法的同步同樣可以使用這兩個指令來實現。monitorenter指令是在編譯後插入到同步代碼塊的開始位置,而monitorexit是插入到方法結束處和異常處, JVM要保證每個monitorenter必須有對應的monitorexit與之配對。任何對象都有一個 monitor 與之關聯,當且一個monitor 被持有後,它將處於鎖定狀態。線程執行到 monitorenter 指令時,將會嘗試獲取對象所對應的 monitor 的所有權,即嘗試獲得對象的鎖。

4、synchronized 關鍵字

java語言的關鍵字,當它用來修飾一個方法或者一個代碼塊的時候,能夠保證在同一時刻最多只有一個線程執行該段代碼。

一:當兩個併發線程訪問同一個對象object中的這個synchronized(this)同步代碼塊時,一個時間內只能有一個線程得到執行。另一個線程必須等待當前線程執行完這個代碼塊以後才能執行該代碼塊。

二:然而,當一個線程訪問object的一個synchronized(this)同步代碼塊時,另一個線程仍然可以訪問該object中的非synchronized(this)同步代碼塊。

三:尤其關鍵的是,當一個線程訪問object的一個synchronized(this)同步代碼塊時,其他線程對object中所有其它synchronized(this)同步代碼塊的訪問將被阻塞。

四、第三個例子同樣適用其它同步代碼塊。也就是說,當一個線程訪問object的一個synchronized(this)同步代碼塊時,它就獲得了這個object的對象鎖。結果,其它線程對該object對象所有同步代碼部分的訪問都被暫時阻塞。

五、以上規則對其它對象鎖同樣適用.

5、類鎖和對象鎖

java的對象鎖和類鎖:java的對象鎖和類鎖在鎖的概念上基本上和內置鎖是一致的,但是,兩個鎖實際是有很大的區別的。
對象鎖是用於對象實例方法,或者一個對象實例上的,類鎖是用於類的靜態方法或者一個類的class對象上的。我們知道,類的對象實例可以有很多個,但是每個類只有一個class對象,所以不同對象實例的對象鎖是互不幹擾的,但是每個類只有一個類鎖。但是有一點必須註意的是,其實類鎖只是一個概念上的東西,並不是真實存在的,它只是用來幫助我們理解鎖定實例方法和靜態方法的區別的。

  • 類鎖和對象鎖
package com;

public class Person {
    static Person person ;

    /**
     * 類鎖
     */
    public void run1(){
        synchronized( Person.class ) {
            System.out.println( Thread.currentThread().getName()  + "  11-->  " + "a" );
        }
    }

    /**
     * 類鎖
     * 
     * 靜態方法鎖,是類鎖
     */
    public synchronized static void run11(){

    }

    /**
     *  類鎖
     */
    public static void run(){
        
        synchronized ( Person.class ) {
            
        }
    }
    
    /**
     * 對象鎖
     */
    public void run2(){
        synchronized( this ) {
            System.out.println( Thread.currentThread().getName()  + "  22-->  " + "a" );
        }
    }

    /**
     * 對象鎖
     * 普通方法鎖是對象鎖
     */
    public synchronized void run3(){
        System.out.println( Thread.currentThread().getName()  + "  33-->  " + "a" );
    }




}

其實,類鎖修飾方法和代碼塊的效果和對象鎖是一樣的,因為類鎖只是一個抽象出來的概念,只是為了區別靜態方法的特點,因為靜態方法是所有對象實例共用的,所以對應著synchronized修飾的靜態方法的鎖也是唯一的,所以抽象出來個類鎖。類鎖和對象鎖是兩個不一樣的鎖,控制著不同的區域,它們是互不幹擾的。同樣,線程獲得對象鎖的同時,也可以獲得該類鎖,即同時獲得兩個鎖,這是允許的。

這時有一個疑問,既然有了synchronized修飾方法的同步方式,為什麼還需要synchronized修飾同步代碼塊的方式呢?而這個問題也是synchronized的缺陷所在。

synchronized的缺陷:當某個線程進入同步方法獲得對象鎖,那麼其他線程訪問這裡對象的同步方法時,必須等待或者阻塞,這對高併發的系統是致命的,這很容易導致系統的崩潰。如果某個線程在同步方法裡面發生了死迴圈,那麼它就永遠不會釋放這個對象鎖,那麼其他線程就要永遠的等待。這是一個致命的問題。

當然同步方法和同步代碼塊都會有這樣的缺陷,只要用了synchronized關鍵字就會有這樣的風險和缺陷。既然避免不了這種缺陷,那麼就應該將風險降到最低。這也是同步代碼塊在某種情況下要優於同步方法的方面。

例如在某個類的方法裡面:這個類裡面聲明瞭一個對象實例,SynObject so=new SynObject();在某個方法裡面調用了這個實例的方法so.testsy();但是調用這個方法需要進行同步,不能同時有多個線程同時執行調用這個方法。

這時如果直接用synchronized修飾調用了so.testsy();代碼的方法,那麼當某個線程進入了這個方法之後,這個對象其他同步方法都不能給其他線程訪問了。假如這個方法需要執行的時間很長,那麼其他線程會一直阻塞,影響到系統的性能。

如果這時用synchronized來修飾代碼塊:synchronized(so){so.testsy();},那麼這個方法加鎖的對象是so這個對象,跟執行這行代碼的對象沒有關係,當一個線程執行這個方法時,這對其他同步方法時沒有影響的,因為他們持有的鎖都完全不一樣。

一個類的對象鎖和另一個類的對象鎖是沒有關聯的,當一個線程獲得A類的對象鎖時,它同時也可以獲得B類的對象鎖。


個人微信號:zhaoyanjun125 , 歡迎關註


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

-Advertisement-
Play Games
更多相關文章
  • 1 概述 1 概述 軟體架構是一門學問,並且是一門很深邃的學問,從本篇文章開始,我們就來聊聊架構,所用到的主流語言為.NET、Java和php。本篇文章作為架構的開篇文章,主要從廣度上敘述軟體架構的發展與演變,從軟體架構系列第二篇文章開始,將結合具體的產品或項目實例,來與大家分享架構。 本篇文章先簡 ...
  • 使用docker也有段時間了,寫了不少文章與總結,下麵把它整理個目錄出來,方便大家去學習與檢索! docker~學習筆記索引 docker~linux下的部署和基本命令(2017-04-07 22:47) docker~docker-machine的介紹(2017-04-12 12:02) dock ...
  • HP-Socket 是一套通用的高性能 TCP/UDP/HTTP 通信框架,包含服務端組件、客戶端組件和 Agent 組件,廣泛適用於各種不同應用場景的 TCP/UDP/HTTP 通信系統,提供 C/C++、C#、Delphi、E(易語言)、Java、Python 等編程語言介面。HP-Socket... ...
  • 代碼: #import "ViewController.h" @interface ViewController () @end @implementation ViewController - (void)viewDidLoad { [super viewDidLoad]; // Do any a ...
  • 目前將項目中的leancloud的即時通訊改為環信的即時通訊。當引入easeui的時候 出現方法數超過上限的問題。 搜索一下問題,解決方法很簡單。 這裡簡單記錄一下,順序記錄一下此解決方案導致的另一個問題。 一、解決方法數超過64k的問題 問題描述: 解決方案: 1、app目錄下 build.gra ...
  • 思路 思路很簡單,對模型數據操作或則控制界面顯示 先看下json部分數據 這種數據對應的一般都是個tableView, 然後根據章節分開,最終界面如下: 分析 這裡採用UITableViewStylePlain樣式,chapterDtoList對應章,subChapterList對應節。章的話我們使 ...
  • `MBProgressHUD`是一個顯示提示視窗的三方庫,常用於用戶交互、後臺耗時操作等的提示。通過顯示一個提示框,通知用戶操作或任務的執行狀態;同時,利用動畫效果,降低用戶等待的焦慮心理,增強用戶體驗。 本篇文章從源碼角度來看一下 是如何實現的,所用的知識都是比較基礎的,不過還是值得我們學習一下。 ...
  • 近幾年,Retrofit猶如燎原之火搬席卷了整個Android界。要是不懂Retrofit,簡直不好意思出門。。。由於近幾個項目都沒用到Retrofit,無奈只能業餘時間自己擼一下,寫的不好的地方,還請不吝賜教。要集成retrofit,在app的bild.gradle中添加庫以來就可以: 如果需要集 ...
一周排行
    -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.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...