Java多線程synchronized

2021-02-19 中軟IT

本篇主要介紹Java多線程中的同步,也就是如何在Java語言中寫出線程安全的程序,如何在Java語言中解決非線程安全的相關問題。沒錯就是使用synchronized。

如何解決線程安全問題?

那麼一般來說,是如何解決線程安全問題的呢?

基本上所有的併發模式在解決線程安全問題時,都採用「序列化訪問臨界資源」的方案,即在同一時刻,只能有一個線程訪問臨界資源,也稱作同步互斥訪問。

通常來說,是在訪問臨界資源的代碼前面加上一個鎖,當訪問完臨界資源後釋放鎖,讓其他線程繼續訪問。

在Java中,提供了兩種方式來實現同步互斥訪問:synchronized和Lock。

本文主要講述synchronized的使用方法,Lock的使用方法在下一篇博文中講述。

synchronized同步方法

synchronized是Java語言的關鍵字,當它用來修飾一個方法或者一個代碼塊的時候,能夠保證在同一時刻最多只有一個線程執行該段代碼。在了解synchronized關鍵字的使用方法之前,我們先來看一個概念:互斥鎖,顧名思義:能達到互斥訪問目的的鎖。

舉個簡單的例子:如果對臨界資源加上互斥鎖,當一個線程在訪問該臨界資源時,其他線程便只能等待。

在Java中,每一個對象都擁有一個鎖標記(monitor),也稱為監視器,多線程同時訪問某個對象時,線程只有獲取了該對象的鎖才能訪問。

在Java中,可以使用synchronized關鍵字來標記一個方法或者代碼塊,當某個線程調用該對象的synchronized方法或者訪問synchronized代碼塊時,這個線程便獲得了該對象的鎖,其他線程暫時無法訪問這個方法,只有等待這個方法執行完畢或者代碼塊執行完畢,這個線程才會釋放該對象的鎖,其他線程才能執行這個方法或者代碼塊。

synchronized的使用

synchronized代碼塊,被修飾的代碼成為同步語句塊,其作用的範圍是調用這個代碼塊的對象,我們在用synchronized關鍵字的時候,能縮小代碼段的範圍就儘量縮小,能在代碼段上加同步就不要再整個方法上加同步。這叫減小鎖的粒度,使代碼更大程度的並發。

synchronized方法,被修飾的方法成為同步方法,其作用範圍是整個方法,作用對象是調用這個方法的對象。

synchronized靜態方法,修飾一個static靜態方法,其作用範圍是整個靜態方法,作用對象是這個類的所有對象。

synchronized類,其作用範圍是Synchronized後面括號括起來的部分synchronized(className.class),作用的對象是這個類的所有對象。

synchronized(),()中是鎖住的對象, synchronized(this)鎖住的只是對象本身,同一個類的不同對象調用的synchronized方法並不會被鎖住,而synchronized(className.class)實現了全局鎖的功能,所有這個類的對象調用這個方法都受到鎖的影響,此外()中還可以添加一個具體的對象,實現給具體對象加鎖。

synchronized (object) {}

synchronized注意事項

當兩個並發線程訪問同一個對象中的synchronized代碼塊時,在同一時刻只能有一個線程得到執行,另一個線程受阻塞,必須等待當前線程執行完這個代碼塊以後才能執行該代碼塊。兩個線程間是互斥的,因為在執行synchronized代碼塊時會鎖定當前的對象,只有執行完該代碼塊才能釋放該對象鎖,下一個線程才能執行並鎖定該對象。

當一個線程訪問object的一個synchronized(this)同步代碼塊時,另一個線程仍然可以訪問該object中的非synchronized(this)同步代碼塊。(兩個線程使用的是同一個對象)

當一個線程訪問object的一個synchronized(this)同步代碼塊時,其他線程對object中所有其它synchronized(this)同步代碼塊的訪問將被阻塞(同上,兩個線程使用的是同一個對象)。

下面通過代碼來實現:

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

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

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

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

5)每個類也會有一個鎖,它可以用來控制對static數據成員的並發訪問。
並且如果一個線程執行一個對象的非static synchronized方法,另外一個線程需要執行這個對象所屬類的static synchronized方法,此時不會發生互斥現象,因為訪問static synchronized方法佔用的是類鎖,而訪問非static synchronized方法佔用的是對象鎖,所以不存在互斥現象。
代碼如下:

第一個線程裡面執行的是insert方法,不會導致第二個線程執行insert1方法發生阻塞現象。

面試題

當一個線程進入一個對象的synchronized方法A之後,其它線程是否可進入此對象的synchronized方法B?
答:不能。其它線程只能訪問該對象的非同步方法,同步方法則不能進入。因為非靜態方法上的synchronized修飾符要求執行方法時要獲得對象的鎖,如果已經進入A方法說明對象鎖已經被取走,那麼試圖進入B方法的線程就只能在等鎖池(注意不是等待池哦)中等待對象的鎖。

synchronized關鍵字的用法?
答:synchronized關鍵字可以將對象或者方法標記為同步,以實現對對象和方法的互斥訪問,可以用synchronized(對象) { … }定義同步代碼塊,或者在聲明方法時將synchronized作為方法的修飾符。

簡述synchronized 和java.util.concurrent.locks.Lock的異同?
答:Lock是Java 5以後引入的新的API,和關鍵字synchronized相比主要相同點:Lock 能完成synchronized所實現的所有功能;主要不同點:Lock有比synchronized更精確的線程語義和更好的性能,而且不強制性的要求一定要獲得鎖。synchronized會自動釋放鎖,而Lock一定要求程式設計師手工釋放,並且最好在finally 塊中釋放(這是釋放外部資源的最好的地方)

原文作者:嘟嘟MD

原文地址:http://www.jianshu.com/p/9474d64575b0

來源:網絡。若涉及版權問題,煩請原作者聯繫我們,我們會在24小時內刪除處理,謝謝!

中軟高科

微信號:javaedu


(長按上圖,彈出「識別二維碼」後可快速關注)

相關焦點

  • JAVA多線程 集合同步
    休眠時間結束後thread-1進入運行狀態去執行synchronizedArrayList的add(i)方法,但由於synchronizedArrayList已被synchronized限制(你必須清楚的是只有返回的迭代器是非線程安全外,synchronizedArrayList其餘的所有方法都是完全的線程安全的), 因此thread-1必須等待thread-2釋放synchronizedArrayList
  • JAVA中synchronized與static synchronized 的區別
    那麼static synchronized恰好就是要控制類的所有實例的訪問了,static synchronized是限制線程同時訪問jvm中該類的所有實例同時訪問對應的代碼快。          一個日本作者-結成浩的《java多線程設計模式》有這樣的一個列子: pulbic class Something(){     publicsynchronizedvoid isSyncA(){}     publicsynchronizedvoid isSyncB(){}     publicstaticsynchronizedvoid
  • 「轉載」java架構之路(多線程)synchronized詳解以及鎖的膨脹升級...
    上幾次博客,我們把volatile基本都說完了,剩下的還有我們的synchronized,還有我們的AQS,這次博客我來說一下synchronized的使用和原理。synchronized是jvm內部的一把隱式鎖,一切的加鎖和解鎖過程是由jvm虛擬機來控制的,不需要我們認為的幹預,我們大致從了解鎖,到synchronized的使用,到鎖的膨脹升級過程三個角度來說一下synchronized。
  • Java synchronized 詳解
    前言記得剛剛學習Java的時候,遇到多線程情況首先想到的就是synchronized。相對於當時的我們來說,synchronized是那麼的神奇而強大,同時它也成為我們解決多線程情況百試不爽的良藥。但是,隨著我們學習的進行,我們知道synchronized是一個重量級的鎖,相對於java.util.concurrent.locks包中提供的各種鎖來說,它顯得那麼的笨重,以至於我們認為它不是那麼的高效而慢慢摒棄它。為了減少重量級鎖的使用,JDK1.6以後,對synchronized相關內容做了一些優化,引入了「偏向鎖」、「輕量級鎖」等內容。
  • Java多線程:由淺入深看synchronized的底層實現原理
    我會從常見的synchronized加鎖方式入手;引出Java對象在內存的布局,以及鎖的存放位置;然後看一看鎖在C++中的簡單實現思路;最後咱們從字節碼中,看一下JVM如果識別synchronized。內容不是很難,不會涉及到特別多深奧的內容,大部分是平鋪直敘的介紹,很適合閱讀呦~小A:快點開始吧,我等不及啦。
  • Java之戳中痛點之 synchronized 深度解析|java|override|author|...
    2、地位  3、不控制並發的影響  測試:兩個線程同時a++,猜一下結果  package cn.jsonshare.java.base.synchronizedtest;  /*** 不使用synchronized,兩個線程同時a++** @author JSON*/public
  • Java面試題-多線程篇十三
    線程是作業系統能夠進行運算調度的最小單位,它被包含在進程之中,是進程中的實際運作單位。程式設計師可以通過它進行多處理器編程,你可以使用多線程對運算密集型任務提速。比如,如果一個線程完成一個任務要100毫秒,那麼用十個線程完成改任務只需10毫秒。122,線程和進程有什麼區別?
  • Java之戳中痛點之 synchronized 深度解析
    2、☞ 《Java面試手冊》.PDF    點擊查看作者:Json_wangqiangcnblogs.com/JsonShare/p/11433302.html概覽:簡介:作用、地位、不控制並發的影響用法:對象鎖和類鎖多線程訪問同步方法的7種情況性質:可重入、不可中斷
  • Java並發編程:synchronized
    三.synchronized同步方法或者同步塊若有不正之處,請多多諒解並歡迎批評指正。一.什麼時候會出現線程安全問題?三.synchronized同步方法或者同步塊在了解synchronized關鍵字的使用方法之前,我們先來看一個概念:互斥鎖,顧名思義:能到達到互斥訪問目的的鎖。舉個簡單的例子:如果對臨界資源加上互斥鎖,當一個線程在訪問該臨界資源時,其他線程便只能等待。
  • Java的synchronized 能防止指令重排序嗎?
    「二胖:」 這不就是要考我 synchronized 和volatile 這個我擅長啊,我特意背過的,synchronized 是java提供的一個關鍵字它主要能保證原子性、有序性它的底層主要是通過Monitor來實現的。volatile也是java的一個關鍵字它的主要作用是可以保證可見性。。。。此處省略1000字。
  • Java開發中synchronized的定義及用法
    synchronizedsynchronized是java中用於同步的關鍵字,其典型的作用域如下所示.用於保證test1函數中的被synchronized大括號包裹的代碼同步執行.synchronized作用的對象為SynchronizedExample1的對象實例,例如main函數中的example1以及example2.
  • 使用Lock鎖:java多線程安全問題解決方案之Lock鎖
    今天我們來學習一下Lock鎖,它是java 1.5之後出現的接口 java.util.concurrent.locks.Lock接口Lock實現提供了比使用 synchronized 方法和語句可獲得的更廣泛的鎖定操作,就來釋放鎖和獲取鎖來說,在使用synchronized 方法的時候,我們並不知道什麼時候獲取到了鎖,什麼時候釋放了鎖,而Lock接口不一樣,他提供了專門的獲取鎖和釋放鎖的方法。
  • 「從入門到放棄-Java」並發編程-鎖-synchronized
    簡介上篇【從入門到放棄-Java】並發編程-線程安全中,我們了解到,可以通過加鎖機制來保護共享對象,來實現線程安全。synchronized是java提供的一種內置的鎖機制。通過synchronized關鍵字同步代碼塊。
  • Java的synchronized的使用
    Java的synchronized的使用Java中的額synchronized關鍵字,大家應該都很熟悉了,多線程中確保線程安全。Java中每個對象都可以作為鎖。一個線程執行同步方法,其他線程對於其他同步方法也是阻塞的,看個例子。
  • 40個Java多線程問題總結
    單核CPU上所謂的」多線程」那是假的多線程,同一時間處理器只會處理一段邏輯,只不過線程之間切換得比較快,看著像多個線程」同時」運行罷了。多核CPU上的多線程才是真正的多線程,它能讓你的多段邏輯同時工作,多線程,可以真正發揮出多核CPU的優勢來,達到充分利用CPU的目的。
  • 最全面的Java多線程用法解析
    最全面的java多線程用法解析,如果你對Java的多線程機制並沒有深入的研究,那麼本文可以幫助你更透徹地理解Java多線程的原理以及使用方法。1.創建線程在Java中創建線程有兩種方法:使用Thread類和使用Runnable接口。在使用Runnable接口時需要建立一個Thread實例。
  • Java 多線程 —— 深入理解 volatile 的原理以及應用
    推薦閱讀:《java 多線程—線程怎麼來的》這一篇主要講解一下volatile的原理以及應用,想必看完這一篇之後,你會對volatile的應用原理以及使用邊界會有更深刻的認知。本篇主要內容:volatile 讀寫同步原理volatile重排序原則volatile應用關鍵字volatile是jvm提供的輕量級的同步機制,但它並不容易理解,而且在多數情況下用不到,被多數開發者拋棄並採用synchronized代替,synchronized屬於重度鎖,如果你對性能有高的要求,那麼同等情況下,變量聲明volatile會減小更少的同步開銷
  • 高級分享:Java多線程你真的理解透徹了嗎?帶你玩轉一次多線程!
    不知道怎麼引入正文相信後端同學在開發的時候多多少少都會涉及到多線程開發,作為Java開發的我也同樣會經常用到多線程開發。我認為Java語言在處理多線程上是非常優秀的,我們可以使用簡明的代碼實現線程的創建、啟動、管理等。
  • Java面試熱點學習:深入並發編程中的synchronized(前三章)
    ,但是在多 線程情況下就可能會出現問題。有序性演示jcstress是java並發壓測工具。代碼I_Result 是一個對象,有一個屬性 r1 用來保存結果,在多線程情況下可能出現幾種結果?Java內存模型的作用Java內存模型是一套在多線程讀寫共享數據時,對共享數據的可見性、有序性、和原子性的規則和保障。
  • Java面試熱點:深入學習並發編程中的synchronized(後三章)
    synchronized不可中斷演示synchronized是不可中斷,處於阻塞狀態的線程會一直等待鎖。5. synchronized能鎖住方法和代碼塊,而Lock只能鎖住代碼塊。6. Lock可以使用讀鎖提高多線程讀效率。7. synchronized是非公平鎖,ReentrantLock可以控制是否是公平鎖。