本文參考自大佬 公衆號:路人甲java
添加鏈接描述
synchronized 的侷限性
synchronized是java內置的關鍵字,它提供了一種獨佔的加鎖方式。synchronized的獲取和釋放鎖由jvm實現,用戶不需要顯示的釋放鎖
如果當前線程獲取不到鎖,那麼會一直阻塞,其他線程也需要一直等待鎖的釋放。除非當前線程執行完成,或者結束阻塞,或者拋出異常,才能釋放鎖,別的線程纔可以繼續爭取鎖
ReentrantLock是Lock的默認實現,在聊ReentranLock之前,我們需要先弄清楚一些概念:
可重入鎖:可重入鎖是指同一個線程可以多次獲得同一把鎖;ReentrantLock和關鍵字Synchronized都是可重入鎖
可中斷鎖:可中斷鎖時只線程在獲取鎖的過程中,是否可以相應線程中斷操作。synchronized是不可中斷的,ReentrantLock是可中斷的
公平鎖和非公平鎖:公平鎖是指多個線程嘗試獲取同一把鎖的時候,獲取鎖的順序按照線程到達的先後順序獲取,而不是隨機插隊的方式獲取。synchronized是非公平鎖,而ReentrantLock是兩種都可以實現,不過默認是非公平鎖
t
ReentrantLock的基本使用(上鎖,保證數據安全)
package juc;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author yanjun.liu
* @date 2020/6/29--19:31
*/
public class MyReentrantLock {
private static ReentrantLock lock=new ReentrantLock();
private static Integer num=0;
public static void add(){
//對於共享變量的操作,需要保證原子性,上鎖
lock.lock();
try {
for(int i=0;i<100000;i++){
num++;
}
}finally {
//解鎖
lock.unlock();
}
}
public static class T extends Thread{
@Override
public void run(){
add();
}
}
public static void main(String[] args) throws Exception{
T t = new T();
T t2 = new T();
T t3 = new T();
t.start();
t2.start();
t3.start();
//main線程進行等待三條線程執行完成,在執行
t.join();
t2.join();
t3.join();
System.out.println(num);
}
}
ReentrantLock的使用過程
創建鎖對象 private static ReentrantLock lock=new ReentrantLock();
上鎖 lock.lock()
解鎖 lock.unlock() 解鎖一定要放在finally中,否則發生異常無法釋放鎖,永久阻塞。。。。。
可重入鎖,同一個線程可以多次獲取同一把鎖,獲幾次,解幾次
改造上面的代碼,加鎖兩次
package juc;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author yanjun.liu
* @date 2020/6/29--19:31
*/
public class MyReentrantLock {
private static ReentrantLock lock=new ReentrantLock();
private static Integer num=0;
public static void add(){
//對於共享變量的操作,需要保證原子性,上鎖
lock.lock();
lock.lock();
try {
for(int i=0;i<100000;i++){
num++;
}
}finally {
//解鎖
lock.unlock();
lock.unlock();
}
}
public static class T extends Thread{
@Override
public void run(){
add();
}
}
public static void main(String[] args) throws Exception{
T t = new T();
T t2 = new T();
T t3 = new T();
t.start();
t2.start();
t3.start();
//main線程進行等待三條線程執行完成,在執行
t.join();
t2.join();
t3.join();
System.out.println(num);
}
}
上鎖lock.lock();一定要放在try{}代碼塊之外,如果在try中上鎖,在上鎖之前,其他代碼拋出異常,那麼就會上鎖失敗,走finally釋放鎖就會拋出異常,因爲壓根就沒上鎖成功
package juc;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author yanjun.liu
* @date 2020/6/29--19:31
*/
public class MyReentrantLock {
private static ReentrantLock lock=new ReentrantLock();
private static Integer num=0;
public static void add(){
try {
//這裏會拋出異常,下面上鎖代碼不會執行
int x=1;
x=1/0;
lock.lock();
lock.lock();
for(int i=0;i<100000;i++){
num++;
}
}finally {
//解鎖會拋出異常
lock.unlock();
lock.unlock();
}
}
public static class T extends Thread{
@Override
public void run(){
add();
}
}
public static void main(String[] args) throws Exception{
T t = new T();
T t2 = new T();
T t3 = new T();
t.start();
t2.start();
t3.start();
//main線程進行等待三條線程執行完成,在執行
t.join();
t2.join();
t3.join();
System.out.println(num);
}
}
上述代碼將拋出IllegalMonitorStateException異常
拋出該異常表明某一線程已經試圖等待對象的監視器,或者試圖通知其他正在等待對象的監視器,然而本身沒有指定的監視器的線程。
Exception in thread "Thread-0" Exception in thread "Thread-1" Exception in thread "Thread-2" java.lang.IllegalMonitorStateException
at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261)
at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:457)
at juc.MyReentrantLock.add(MyReentrantLock.java:26)
at juc.MyReentrantLock$T.run(MyReentrantLock.java:35)
java.lang.IllegalMonitorStateException
at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261)
at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:457)
at juc.MyReentrantLock.add(MyReentrantLock.java:26)
at juc.MyReentrantLock$T.run(MyReentrantLock.java:35)
java.lang.IllegalMonitorStateException
at java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261)
at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:457)
at juc.MyReentrantLock.add(MyReentrantLock.java:26)
at juc.MyReentrantLock$T.run(MyReentrantLock.java:35)
0