一、復習
二、如何避免偽共享
在JDK8之前是使用填充位元組的方式來避免偽共享的,我們最終的目的其實就是希望單個變數能夠獨占一個快取行, 我們舉一個類的例子
package com.ruigege.OtherFoundationOfConcurrent2;
public class FiledLong {
public volatile long value =0L;
public long p1,p2,p3,p4,p5,p6;
}
可以看這個類,如果cache行偽64個位元組,那么正好能夠占滿,七個long型別的變數,其中p1-p6都是用來占位,還有一個物件的頭占用八個位元組,正好64個位元組, 在JDK8中提供了一個注解,用于避免偽共享
@sun.misc.Contended
class FiledLong2{
public volatile long value=https://www.cnblogs.com/ruigege0000/p/0L;
}
用法:既可以用修飾類也可以用來修飾變數,
注意點:@Contended注解只能用于Java的核心類,比如rt包下的類,如果用戶的類需要使用這個注解的時候,需要添加JVM的引數:-XX:-RestrictContended,填充的默認寬度為128,要自定義寬度可以設定-XX:ContendedPaddingWidth引數
三、出現偽共享記憶體的條件
在多執行緒下訪問同一個快取行的多個變數,才會出現偽共享變數的問題,如果在單執行緒下訪問多個變數反而會加速訪問,
四、樂觀鎖和悲觀鎖
1.悲觀鎖
定義:悲觀鎖認為外界對資料的修改持保守態度,認為資料很容易被外界修改,在資料被處理之前必須先加鎖,這種鎖是排他鎖,一個執行緒獲取了鎖之后,其他執行緒只能等待或者拋出例外,獲取鎖的執行緒,對記錄進行操作,然后提交事務釋放鎖,下面舉一個例子
//使用悲觀鎖來獲取
EntryObject entry = query("select * from table1 where id =#{id} for update",id);
//修改記錄內容,根據計算修改entry記錄的屬性
String name=generatorName(entry);
entry.setName(name);
//update操作
int count = updateZ("update table1 set name=#{name},age=#{age} where id=#{id}",entry);
return count;
對于上面的代碼,使用了事務切面的方法,只要進入這個方法種就開始執行事物一直到這個方法結束,多個執行緒呼叫這個方法的時候,只有一個執行緒能夠獲取鎖,其他執行緒就會阻塞掛起,直到原執行緒釋放鎖 樂觀鎖是相對悲觀鎖而存在的的方式,一般認為如果只是訪問資料那么就是可以不用加鎖,只有要更新資料的時候,才會正式對資料沖突與否進行檢測,具體來說,根據update回傳的行數讓用戶決定如何去做,將上面的例子改為樂觀鎖,
package com.ruigege.OtherFoundationOfConcurrent2;
public class UpdateEntry2 {
public int updateEntry(long id) {
//使用樂觀鎖獲取指定記錄
EntryObject entry = query("select * from table1 where id=#{id}",id);
//
String name = generatorName(entry);
entry.setName(name);
//update操作
int count = update("update table1 set name=#{name},age=#{age},version=${version}+1 where id=#{id} and version =#{version}",entry);
return count;
}
}
對比上面的代碼就可以知道根據version來進行更新資料,更新成功的話,就會給version+1,其他執行緒進行更新的時候,如果vesion不對的話,那么就會停止更新,我們也是使用不斷地回圈來獲取鎖而解決更新的問題
package com.ruigege.OtherFoundationOfConcurrent2;
public class updateEntry3 {
boolean result = false;
int retryNum = 5;
while(retryNum>0) {
//使用樂觀鎖獲取記錄
EntryObject entry = query("select * from table1 where id=#{id}",id);
String name = generatorName(entry);
entry.setName(name);
//update操作
int count = update("update table1 set name=#{name},age=#{age},version=${version}+1 where id=#{id} and version =#{version}",entry);
//回傳的行如果不是0的話說明更新成功了,那么即刻跳出回圈
if(count == 1) {
result = true;
break;
}
retryNum--;
}
return result;
}
樂觀鎖并不會使用資料庫提供的鎖機制,一般在表中添加version欄位或者使用業務狀態來實作,樂觀鎖直到提交時才鎖定,所以不會產生任何死鎖,
五、公平鎖和非公平鎖
公平鎖表示執行緒獲取鎖的順序是按照先到先得的原則,非公平鎖在運行的時候闖入,也就是不一定先到先得, ReentrantLock提供了公平和非公平鎖,
六 、原始碼:
所在包:com.ruigege.OtherFoundationOfConcurrent2 https://github.com/ruigege66/ConcurrentJavaCSDN:https://blog.csdn.net/weixin_44630050 博客園:https://www.cnblogs.com/ruigege0000/ 歡迎關注微信公眾號:傅里葉變換,個人賬號,僅用于技術交流 
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/228692.html
標籤:Java
上一篇:springioc實作分析到一個簡易的手寫框架--2020/12/2
下一篇:Java通過IO流輸出檔案目錄
