synchronized在語法上已經足夠簡單了,在JDK 5之前只能藉助此實現,但是由於是獨佔鎖,性能卻不高,因此JDK 5以後就開始藉助於JNI來完成更高級的鎖實現。
JDK 5中的鎖是接口java.util.concurrent.locks.Lock。
另外java.util.concurrent.locks.ReadWriteLock提供了一對可供讀寫併發的鎖。
線程獲取鎖和釋放鎖的方法。
java.util.concurrent.locks.Lock類,既然是鎖,肯定有用於線程獲取鎖和釋放鎖的方法存在,這兩個方法爲:
1、void lock();
函數功能:獲取鎖。如果鎖不可用,由於線程調度目的,將禁用此線程,並且在獲得鎖之前,該線程將一直處於休眠狀態。
2、unlock();
函數功能:釋放鎖。對應於所有的獲取鎖,例如lock()、tryLock()、tryLock(xx)、lockInterruptibly()等操作,如果成功的話應該對應着一個unlock(),這樣可以避免死鎖或者資源浪費。
join() 在實際使用過程中,我們可以通過join方法來等待線程執行的結果,其實有點類似future/callable的功能。
出現了數據重複問題,明顯可見存在線程安全問題;
add()方法中 a++; 並不是一個原子性操作,我們使用原子類把int a變成一個原子類。我們對數值的一些非原子性操作,都可以使用原子類轉化爲原子性操作。
1、使用Lock同步來模擬AtomicInteger類
public class AtomicIntegerLock {
private volatile int value;
//獲取一個鎖實例
private Lock lock = new ReentrantLock();
public AtomicIntegerLock(int value) {
this.value = value;
}
//同一時刻只能有一個線程修改值
public void set(int newValue) {
lock.lock();
try {
this.value = newValue;
} finally {
lock.unlock();
}
}
//獲取值
public final int get() {
lock.lock();
try {
return value;
} finally {
lock.unlock();
}
}
public final int getAndSet(int newValue) {
lock.lock();
try {
int oldValue = value;
value = newValue;
return oldValue;
} finally {
lock.unlock();
}
}
/**
* 返回舊值並增加
*
* @param delta
* @return
*/
public final int getAndAdd(int delta) {
lock.lock();
try {
int oldValue = value;
value += delta;
return oldValue;
} finally {
lock.unlock();
}
}
/**
* 先增加再返回新值
*
* @param delta
* @return
*/
public final int addAndGet(int delta) {
lock.lock();
try {
value += delta;
return value;
} finally {
lock.unlock();
}
}
/**
* 比較是否可預期值相同
*
* @param expect
* @param newValue
* @return
*/
public final boolean getAndCompare(int expect, int newValue) {
lock.lock();
try {
if (this.value == expect) {
value = newValue;
return true;
} else {
return false;
}
} finally {
lock.unlock();
}
}
/**
* 先獲取value的值,在遞增1;
* @return
*/
public final int getAndIncrement(){
lock.lock();
try {
return value++;
} finally {
lock.unlock();
}
}
/**
* 先獲取value的值,然後減1
* @return
*/
public final int getAndDecrement(){
lock.lock();
try {
return value--;
} finally {
lock.unlock();
}
}
/**
* 先自增1,在返回新值
* @return
*/
public final int incrementAndGet(){
lock.lock();
try {
return ++value;
} finally {
lock.unlock();
}
}
/**
* 先遞減1,在返回值
* @return
*/
public final int decrementAndGet(){
lock.lock();
try {
return --value;
} finally {
lock.unlock();
}
}
public final String toString(){
lock.lock();
return Integer.toString(get());
}
}
2、Lock同步和synchronized同步兩種鎖的性能:使用lock的性能要好。與其說ReentrantLock性能好,還不如說synchronized還有很大優化的餘地。
3、用Lock來進行同步計數和使用AtomicInteger類計數的性能比較;使用CAS指令確實更要快的多。
/**
* Created on 2020/4/28 16:30
* author:crs
* Description:測試兩種同步性能的差別
*/
public class TestAtomicIntegerLock {
private static int synValue = 0;
public static void main(String[] args) {
int threadNum = 10;
int maxValue = 1000000;
Thread[] t = new Thread[threadNum];
//返回的是納秒 //System.nanoTime();
Long begin = System.currentTimeMillis();
for (int i = 0; i <threadNum ; i++) {
AtomicIntegerLock aIL = new AtomicIntegerLock(0);
//創建了十個線程,每個線程的任務確定
t[i]=new Thread(new Runnable() {
@Override
public void run() {
for(int j=0;j<maxValue;j++){
aIL.getAndIncrement();
}
}
});
}
for(int i=0;i<threadNum;i++){
t[i].start();
}
//main線程等待前面開啓的所有線程結束
for(int i=0;i<threadNum;i++){
try {
t[i].join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("使用lock所花費的時間爲:"+(System.currentTimeMillis()-begin));
int[] lock = new int[0];
begin = System.currentTimeMillis();
for(int i=0;i<threadNum;i++){
synValue = 0;
t[i]=new Thread(new Runnable(){
@Override
public void run() {
for(int j=0;j<maxValue;j++){
synchronized(lock){
++synValue;
}
}
}
});
}
for(int i=0;i<threadNum;i++){
t[i].start();
}
//main線程等待前面開啓的所有線程結束
for(int i=0;i<threadNum;i++){
try {
t[i].join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(synValue);
System.out.println("使用synchronized所花費的時間爲:"+(System.currentTimeMillis()-begin));
begin = System.currentTimeMillis();
for(int i=0;i<threadNum;i++){
AtomicInteger ai = new AtomicInteger(0);
t[i]=new Thread(new Runnable(){
@Override
public void run() {
for(int j=0;j<maxValue;j++){
ai.incrementAndGet();
}
}
});
}
for(int i=0;i<threadNum;i++){
t[i].start();
}
//main線程等待前面開啓的所有線程結束
for(int i=0;i<threadNum;i++){
try {
t[i].join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println("使用原子操作類AtomicInteger所花費的時間爲:"+(System.currentTimeMillis()-begin));
}
}