大家好,今天來為大家解答synchronized修飾方法這個問題的一些問題點,包括synchronized鎖代碼塊也一樣很多人還不知道,因此呢,今天就來為大家分析分析,現在讓我們一起來看看吧!如果解決了您的問題,還望您關注下本站哦,謝謝~
Spring如何更好地解決線程安全問題
線程安全問題概述賣票問題分析單窗口賣票
一個窗口(單線程)賣100張票沒有問題
單線程程序是不會出現線程安全問題的
多個窗口賣不同的票3個窗口一起賣票,賣的票不同,也不會出現問題
多線程程序,沒有訪問共享數據,不會產生問題
多個窗口賣相同的票3個窗口賣的票是一樣的,就會出現安全問題
多線程訪問了共享的數據,會產生線程安全問題
線程安全問題代碼實現模擬賣票案例
創建3個線程,同時開啟,對共享的票進行出售
線程安全問題原理分析分析:線程安全問題正常是不允許產生的,我們可以讓一個線程在訪問共享數據的時候,無論是否失去了cpu的執行權;讓其他的線程只能等待,等待當前線程賣完票,其他線程在進行賣票。
解決線程安全問題辦法1-synchronized同步代碼塊同步代碼塊:synchronized關鍵字可以用于方法中的某個區塊中,表示只對這個區塊的資源實行互斥訪問。
使用synchronized同步代碼塊格式:
synchronized(鎖對象){可能會出現線程安全問題的代碼(訪問了共享數據的代碼)}
代碼實現如下:
注意:
代碼塊中的鎖對象,可以使用任意的對象。但是必須保證多個線程使用的鎖對象是同一個。鎖對象作用:把同步代碼塊鎖住,只讓一個線程在同步代碼塊中執行。同步技術原理分析同步技術原理:
使用了一個鎖對象,這個鎖對象叫同步鎖,也叫對象鎖,也叫對象監視器
3個線程一起搶奪cpu的執行權,誰搶到了誰執行run方法進行賣票。
t0搶到了cpu的執行權,執行run方法,遇到synchronized代碼塊這時t0會檢查synchronized代碼塊是否有鎖對象發現有,就會獲取到鎖對象,進入到同步中執行
t1搶到了cpu的執行權,執行run方法,遇到synchronized代碼塊這時t1會檢查synchronized代碼塊是否有鎖對象發現沒有,t1就會進入到阻塞狀態,會一直等待t0線程歸還鎖對象,t0線程執行完同步中的代碼,會把鎖對象歸還給同步代碼塊t1才能獲取到鎖對象進入到同步中執行
總結:同步中的線程,沒有執行完畢不會釋放鎖,同步外的線程沒有鎖進不去同步。
解決線程安全問題辦法2-synchronized普通同步方法同步方法:使用synchronized修飾的方法,就叫做同步方法,保證A線程執行該方法的時候,其他線程只能在方法外等著。
格式:
publicsynchronizedvoidpayTicket(){可能會出現線程安全問題的代碼(訪問了共享數據的代碼)}
代碼實現:
分析:定義一個同步方法,同步方法也會把方法內部的代碼鎖住,只讓一個線程執行。
同步方法的鎖對象是誰?
就是實現類對象newRunnableImpl(),也是就是this,所以同步方法是鎖定的this對象。
解決線程安全問題辦法3-synchronized靜態同步方法同步方法:使用synchronized修飾的方法,就叫做同步方法,保證A線程執行該方法的時候,其他線程只能在方法外等著。對于static方法,我們使用當前方法所在類的字節碼對象(類名.class)。
格式:
publicstaticsynchronizedvoidpayTicket(){可能會出現線程安全問題的代碼(訪問了共享數據的代碼)}
代碼實現:
分析:靜態的同步方法鎖對象是誰?
不能是this,this是創建對象之后產生的,靜態方法優先于對象
靜態方法的鎖對象是本類的class屬性–>class文件對象(反射)。
解決線程安全問題辦法4-Lock鎖Lock接口中的方法:
publicvoidlock():加同步鎖。publicvoidunlock():釋放同步鎖使用步驟:
在成員位置創建一個ReentrantLock對象在可能會出現安全問題的代碼前調用Lock接口中的方法lock獲取鎖在可能會出現安全問題的代碼后調用Lock接口中的方法unlock釋放鎖代碼實現:
分析:java.util.concurrent.locks.Lock接口
Lock實現提供了比使用synchronized方法和語句可獲得的更廣泛的鎖定操作。相比Synchronized,ReentrantLock類提供了一些高級功能,主要有以下3項:
等待可中斷,持有鎖的線程長期不釋放的時候,正在等待的線程可以選擇放棄等待,這相當于Synchronized來說可以避免出現死鎖的情況。通過lock.lockInterruptibly()來實現這個機制。公平鎖,多個線程等待同一個鎖時,必須按照申請鎖的時間順序獲得鎖,Synchronized鎖非公平鎖,ReentrantLock默認的構造函數是創建的非公平鎖,可以通過參數true設為公平鎖,但公平鎖表現的性能不是很好。公平鎖、非公平鎖的創建方式:
鎖綁定多個條件,一個ReentrantLock對象可以同時綁定多個對象。ReenTrantLock提供了一個Condition(條件)類,用來實現分組喚醒需要喚醒的線程們,而不是像synchronized要么隨機喚醒一個線程要么喚醒全部線程。ReentrantLock和Synchronized的區別相同點:
它們都是加鎖方式同步;都是重入鎖;阻塞式的同步;也就是說當如果一個線程獲得了對象鎖,進入了同步塊,其他訪問該同步塊的線程都必須阻塞在同步塊外面等待,而進行線程阻塞和喚醒的代價是比較高的(操作系統需要在用戶態與內核態之間來回切換,代價很高,不過可以通過對鎖優化進行改善);Synchronized鎖在Spring事務管理下,為什么線程不安全
先簡單提示下,關于synchronized關鍵字,一定要慎用,非常影響性能。
首先說明下,synchronized是Java中的關鍵字,是一種同步鎖。它修飾的對象有以下幾種:
1.修飾一個代碼塊,被修飾的代碼塊稱為同步語句塊,其作用的范圍是大括號{}括起來的代碼,作用的對象是調用這個代碼塊的對象;
2.修飾一個方法,被修飾的方法稱為同步方法,其作用的范圍是整個方法,作用的對象是調用這個方法的對象;
3.修改一個靜態的方法,其作用的范圍是整個靜態方法,作用的對象是這個類的所有對象;
4.修改一個類,其作用的范圍是synchronized后面括號括起來的部分,作用主的對象是這個類的所有對象
我們再簡單的說下spring的事務相關
Spring在不同的事務管理API之上定義了一個抽象層。而應用程序開發人員不必了解底層的事務管理API,就可以使用Spring的事務管理機制。
Spring既支持編程式事務管理(也稱編碼式事務),也支持聲明式的事務管理
編程式事務管理:將事務管理代碼嵌入到業務方法中來控制事務的提交和回滾,在編程式事務中,必須在每個業務操作中包含額外的事務管理代碼
聲明式事務管理:大多數情況下比編程式事務管理更好用。它將事務管理代碼從業務方法中分離出來,以聲明的方式來實現事務管理。事務管理作為一種橫切關注點,可以通過AOP方法模塊化。Spring通過SpringAOP框架支持聲明式事務管理。
Spring并不直接管理事務,而是提供了多種事務管理器,它們將事務管理的職責委托給JTA或其他持久化機制所提供的平臺相關的事務實現。每個事務管理器都會充當某一特定平臺的事務實現的門面,這使得用戶在Spring中使用事務時,幾乎不用關注實際的事務實現是什么。
spring的事務的具體配置方法這里就不贅述了。
在Spring中,聲明式事務是通過事務屬性來定義的,事務屬性描述了事務策略如何應用到方法上。事務屬性包含了5個方面,盡管Spring提供了多種聲明式事務的機制,但是所有的方式都依賴這五個參數來控制如何管理事務策略。聲明式事務通過傳播行為,隔離級別,只讀提示,事務超時及回滾規則來進行定義。
隔離級別定義了一個事務可能受其他并發事務影響的程度。在典型的應用程序中,多個事務并發運行,經常會操作相同的數據來完成各自的任務。并發,雖然是必須的,可是會導致下面的問題。①臟讀(Dirtyreads):臟讀發生在一個事務讀取了另一個事務改寫但尚未提的數據時。如果改寫在稍后被回滾了,那么第一個事務獲取的數據就是無效的。
②不可重復讀(Nonrepeatableread):不可重復讀發生在一個事務執行相同的查詢兩次或兩次以上,但是每次都得到不同的數據時。這通常是因為另一個并發事務在兩次查詢期間更新了數據
③幻讀(Phantomread):幻讀與不可重復讀類似。它發生在一個事務(T1)讀取了幾行數據,接著另一個并發事務(T2)插入了一些數據時。在隨后的查詢中,第一個事務(T1)就會發現多了一些原本不存在的記錄
Spring事務的底層是SpringAOP,而SpringAOP的底層是動態代理技術
簡單來說就是在調用方法前開啟事務,調用方法后提交事務。
在多線程環境下,就可能會出現:方法執行完了(synchronized代碼塊執行完了),事務還沒提交,別的線程可以進入被synchronized修飾的方法,再讀取的時候,讀到的是還沒提交事務的數據,這個數據不是最新的,所以就出現了這個問題。
從上面來看,問題就是兩者同時使用時,加鎖沒有包括整個事務。所以解決方法就是將synchronized的鎖加到整個spring事務上,就不會出現線程安全的問題了。
最后,我會一直在頭條分享我的學習筆記,關注,點贊和轉發就是對我最大的支持。
java什么是構造方法,作用是什么
構造方法是一種特殊的方法,與一般的方法不同是:
1.構造方法的名字必須與定義他的類名完全相同,沒有返回類型,甚至連void也沒有。
2.構造方法的調用是在創建一個對象時使用new操作進行的。
3.構造方法不能被static、final、synchronized、abstract和native修飾。構造方法不能被子類繼承。
構造方法的作用:
構造方法分為有參數和沒有參數兩種。
有參數的構造方法主要就是用于對創建出來的對象進行初始化,避免了某些屬性忘記初始化的問題;同時提高了程序的可閱讀性。
另一種是沒有參數的構造方法,又叫缺省構造方法。其實,你的類如果沒有定義任何構造方法,Java的編譯器會配上一個自動缺省構造方法,這個構造方法是空的,不做任何事情,只是為了滿足編譯需要。或者,你也可以自己寫一個空的構造方法,在里邊對一些屬性賦值,或者執行一些其他操作。
其實,構造方法的主要作用就是為對象成員變量賦初始值。
stringbuffer與stringbuilder的區別
區別1、StringBuffer與StringBuilder中的方法和功能完全是等價的,2、只是StringBuffer中的方法大都采用了synchronized關鍵字進行修飾,因此是線程安全的,而StringBuilder沒有這個修飾,可以被認為是線程不安全的。
3、在單線程程序下,StringBuilder效率更快,因為它不需要加鎖,不具備多線程安全而StringBuffer則每次都需要判斷鎖,效率相對更低
好了,本文到此結束,如果可以幫助到大家,還望關注本站哦!