您好,登錄后才能下訂單哦!
這期內容當中小編將會給大家帶來有關java中怎么實現鎖的雙重檢測,文章內容豐富且以專業的角度為大家分析和敘述,閱讀完這篇文章希望大家可以有所收獲。
雙重檢測鎖定模式是一種設計模式,我們通過首次檢測鎖定條件而不是實際獲得鎖從而減少獲取鎖的開銷。
雙重檢查鎖定模式用法通常用于實現執行延遲初始化的單例工廠模式。延遲初始化推遲了成員字段或成員字段引用的對象的構造,直到實際需要才真正的創建。
但是我們需要非常小心的使用雙重檢測模式,以避免發送錯誤。
先看一個在單線程正常工作的單例模式:
public class Book {
private static Book book;
public static Book getBook(){
if(book==null){
book = new Book();
}
return book;
}
}
上面的類中定義了一個getBook方法來返回一個新的book對象,返回對象之前,我們先判斷了book是否為空,如果不為空的話就new一個book對象。
初看起來,好像沒什么問題,我們仔細考慮一下:
book=new Book()其實一個復雜的命令,并不是原子性操作。它大概可以分解為1.分配內存,2.實例化對象,3.將對象和內存地址建立關聯。
在多線程環境中,因為重排序的影響,我們可能的到意向不到的結果。
最簡單的辦法就是加上synchronized關鍵字:
public class Book {
private static Book book;
public synchronized static Book getBook(){
if(book==null){
book = new Book();
}
return book;
}
}
如果要使用double check模式該怎么做呢?
public class BookDLC {
private static BookDLC bookDLC;
public static BookDLC getBookDLC(){
if(bookDLC == null ){
synchronized (BookDLC.class){
if(bookDLC ==null){
bookDLC=new BookDLC();
}
}
}
return bookDLC;
}
}
我們先判斷bookDLC是否為空,如果為空,說明需要實例化一個新的對象,這時候我們鎖住BookDLC.class,然后再進行一次為空判斷,如果這次不為空,則進行初始化。
那么上的代碼有沒有問題呢?
有,bookDLC雖然是一個static變量,但是因為CPU緩存的原因,我們并不能夠保證當前線程被賦值之后的bookDLC,立馬對其他線程可見。
所以我們需要將bookDLC定義為volatile,如下所示:
public class BookDLC {
private volatile static BookDLC bookDLC;
public static BookDLC getBookDLC(){
if(bookDLC == null ){
synchronized (BookDLC.class){
if(bookDLC ==null){
bookDLC=new BookDLC();
}
}
}
return bookDLC;
}
}
public class BookStatic {
private static BookStatic bookStatic= new BookStatic();
public static BookStatic getBookStatic(){
return bookStatic;
}
}
JVM在類被加載之后和被線程使用之前,會進行靜態初始化,而在這個初始化階段將會獲得一個鎖,從而保證在靜態初始化階段內存寫入操作將對所有的線程可見。
上面的例子定義了static變量,在靜態初始化階段將會被實例化。這種方式叫做提前初始化。
下面我們再看一個延遲初始化占位類的模式:
public class BookStaticLazy {
private static class BookStaticHolder{
private static BookStaticLazy bookStatic= new BookStaticLazy();
}
public static BookStaticLazy getBookStatic(){
return BookStaticHolder.bookStatic;
}
}
上面的類中,只有在調用getBookStatic方法的時候才會去初始化類。
我們知道ThreadLocal就是Thread的本地變量,它實際上是對Thread中的成員變量ThreadLocal.ThreadLocalMap的封裝。
所有的ThreadLocal中存放的數據實際上都存儲在當前線程的成員變量ThreadLocal.ThreadLocalMap中。
如果使用ThreadLocal,我們可以先判斷當前線程的ThreadLocal中有沒有,沒有的話再去創建。
如下所示:
public class BookThreadLocal {
private static final ThreadLocal<BookThreadLocal> perThreadInstance =
new ThreadLocal<>();
private static BookThreadLocal bookThreadLocal;
public static BookThreadLocal getBook(){
if (perThreadInstance.get() == null) {
createBook();
}
return bookThreadLocal;
}
private static synchronized void createBook(){
if (bookThreadLocal == null) {
bookThreadLocal = new BookThreadLocal();
}
perThreadInstance.set(bookThreadLocal);
}
}
上述就是小編為大家分享的java中怎么實現鎖的雙重檢測了,如果剛好有類似的疑惑,不妨參照上述分析進行理解。如果想知道更多相關知識,歡迎關注億速云行業資訊頻道。
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。