一、 原來代碼
-
示例代碼:
private static org.bouncycastle.jce.provider.BouncyCastleProvider bouncyCastleProvider = null; public static org.bouncycastle.jce.provider.BouncyCastleProvider getBouncyCastleProviderInstance() { if (bouncyCastleProvider == null) { bouncyCastleProvider = new org.bouncycastle.jce.provider.BouncyCastleProvider(); } return bouncyCastleProvider; }
二、 優化後代碼
-
示例代碼:
private static volatile org.bouncycastle.jce.provider.BouncyCastleProvider bouncyCastleProvider ; public static org.bouncycastle.jce.provider.BouncyCastleProvider getBouncyCastleProviderInstance() { if (bouncyCastleProvider == null) { synchronized(org.bouncycastle.jce.provider.BouncyCastleProvider.class){ if(bouncyCastleProvider == null){ bouncyCastleProvider = new org.bouncycastle.jce.provider.BouncyCastleProvider(); } } } return bouncyCastleProvider; }
三、實現原理
-
添加synchronized關鍵字。添加到同步代碼塊中,而不是如下:
public static synchronized org.bouncycastle.jce.provider.BouncyCastleProvider getBouncyCastleProviderInstance() { if (bouncyCastleProvider == null) { bouncyCastleProvider = new org.bouncycastle.jce.provider.BouncyCastleProvider(); } return bouncyCastleProvider; }
-
目的:即:保證在同一時刻最多隻有一個線程執行該段代碼,達到保證併發安全的效果。
四 、 synchronized
-
定義
- synchronized鎖是重量級鎖,重量級體現在活躍性差一點。synchronized鎖是內置鎖,意味着JVM能基於synchronized鎖做一些優化:比如增加鎖的粒度(鎖粗化)、鎖消除。
- synchronized鎖釋放是自動的,當線程執行退出synchronized鎖保護的同步代碼塊時,會自動釋放synchronized鎖。
- 線程在競爭synchronized鎖時是非公平的。
-
synchronized Java中的關鍵字,是一種同步鎖。它修飾的對象有以下幾種:
- 修飾一個代碼塊,被修飾的代碼塊稱爲同步語句塊,其作用的範圍是大括號{}括起來的代碼,作用的對象是調用這個代碼塊的對象;
- 修飾一個方法,被修飾的方法稱爲同步方法,其作用的範圍是整個方法,作用的對象是調用這個方法的對象;
- 修飾一個靜態的方法,其作用的範圍是整個靜態方法,作用的對象是這個類的所有對象;
- 修飾一個類,其作用的範圍是synchronized後面括號括起來的部分,作用主的對象是這個類的所有對象。
-
使用
-
1、 普通同步方法,鎖的是當前實例的對象
- 同步方法鎖住的是調用方法的對象;新創建的對象調用方法,和之前的方法不同步。
class mYread implements Runnable { private static int count; public mYread() { count = 0; } public synchronized void method() { for (int i = 0; i < 5; i ++) { try { System.out.println(Thread.currentThread().getName() + ":" + (count++)); Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } public synchronized void run() { method(); } } //執行調用 mYread read1 = new mYread(); mYread read2 = new mYread(); Thread thread1 = new Thread(read1, "mYread1"); Thread thread2 = new Thread(read2, "mYread2"); thread1.start(); thread2.start(); read1 和 read2 是兩個對象,thread1和thread2執行不會保持線程同步。 ``` - 2、 靜態同步方法,鎖的是靜態方法所在的類對象 - 靜態同步方法鎖的是類的對象,新創建的對象也是被鎖的對象。
class mYread implements Runnable { private static int count; public mYread() { count = 0; } public synchronized static void method() { for (int i = 0; i < 5; i ++) { try { System.out.println(Thread.currentThread().getName() + ":" + (count++)); Thread.sleep(100); } catch (InterruptedException e) { e.printStackTrace(); } } } public synchronized void run() { method(); } } //執行調用 mYread read1 = new mYread(); mYread read2 = new mYread(); Thread thread1 = new Thread(read1, "mYread1"); Thread thread2 = new Thread(read2, "mYread2"); thread1.start(); thread2.start(); read1 和 read2 是兩個對象,但在thread1和thread2併發執行時卻保持了線程同步。 ```
- 3、 同步代碼塊,鎖的是括號裏的對象。(此處的可以是實例對象,也可以是類的class對象。)
-
指定給某個對象加鎖
如果有一個明確的對象:
public abstract class RSACoderUtils extends CoderUtils { if (bouncyCastleProvider == null) { synchronized(org.bouncycastle.jce.provider.BouncyCastleProvider.class){ if(bouncyCastleProvider == null){ bouncyCastleProvider = new org.bouncycastle.jce.provider.BouncyCastleProvider(); } } } }
如果沒有一個明確的對象:
public abstract class RSACoderUtils extends CoderUtils { if (bouncyCastleProvider == null) { private byte[] lock = new byte[0]; // 特殊的instance變量 synchronized(lock){ if(bouncyCastleProvider == null){ bouncyCastleProvider = new org.bouncycastle.jce.provider.BouncyCastleProvider(); } } } }
-. 比較兩種創建對象的消耗:
Object lock = new Object(); private byte[] lock = new byte[0];
通過查看編譯後的字節碼:生成零長度的byte[]的lock需要3行操作碼,Object 的lock 則需要7行操作碼,故零長度的byte數組對象創建性能更好。
-
給某個類加鎖
public abstract class RSACoderUtils extends CoderUtils { public void test(){ synchronized(RSACoderUtils.class){ if(bouncyCastleProvider == null){ bouncyCastleProvider = new org.bouncycastle.jce.provider.BouncyCastleProvider(); } } } }
-
五、volatile
- 禁止指令重排序優化
- 保證此變量對所有線程的可 見性,這裏的“可見性”是指當一條線程修改了這個變量的值,新值對於其他線程來說是可以 立即得知的。
六、 單例模式
- 保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。
- 懶漢模式 :
public class Monitor {
private static Monitor monitor = null;
private static volatile Monitor monitor = null; //
private Monitor() {}
public static Monitor getMonitor() {
if (monitor == null) {
synchronized (Monitor.class) {
if (monitor == null) {
monitor = new Monitor();
}
}
}
return monitor;
}
}
- 餓漢模式:
public class Monitor {
private static Monitor monitor = new Monitor ();
private Monitor () {}
public static Monitor getMonitor() {
return monitor;
}
}
更多內容,阿里博客地址:
https://yq.aliyun.com/users/article?spm=a2c4e.11153940.headeruserinfo.3.2b9f291a9z4pJ7
歡迎關注公衆號,查看更多內容 :
volatile 關鍵字的詳細介紹;
synchronized 關鍵字的詳解;