①. 可重入鎖
1>. 可重入鎖(遞回鎖)
-
①. 指的是同一執行緒外層函式獲得鎖后,再進入該執行緒的內層方法會自動獲取鎖 (
前提,鎖物件是同一個物件)
類似于家里面的大門,進入之后可以進入廁所、廚房等 -
②. Java中ReentranLock(顯示鎖)和synchronized(隱式鎖)都是可重入鎖,可重入鎖的一個優點是可在一定程度避免死鎖
-
③.
隱式鎖:(即synchronized關鍵字使用的鎖)默認是可重入鎖(同步塊、同步方法)
原理如下:掌握
- 每個鎖物件擁有一個鎖計數器和一個指向持有該鎖的執行緒的指標
- 當執行monitorenter時,如果目標鎖物件的計數器為零,那么說明它沒有被其他執行緒持有,Java虛擬機會將該鎖物件的持有執行緒設定為當前執行緒,并且將其計數器加1,否則需要等待,直至持有執行緒釋放該鎖
- 當執行monitorexit時,Java虛擬機則鎖物件的計數器減1,計數器為零代表鎖已經被釋放

//1.同步塊
public class SychronizedDemo {
Object object=new Object();
public void sychronizedMethod(){
new Thread(()->{
synchronized (object){
System.out.println(Thread.currentThread().getName()+"\t"+"外層....");
synchronized (object){
System.out.println(Thread.currentThread().getName()+"\t"+"中層....");
synchronized (object){
System.out.println(Thread.currentThread().getName()+"\t"+"內層....");
}
}
}
},"A").start();
}
public static void main(String[] args) {
new SychronizedDemo().sychronizedMethod();
/*
輸出結果:
A 外層....
A 中層....
A 內層....
* */
}
}
//2.同步代碼塊
class Phone{
public synchronized void sendSms() throws Exception{
System.out.println(Thread.currentThread().getName()+"\tsendSms");
sendEmail();
}
public synchronized void sendEmail() throws Exception{
System.out.println(Thread.currentThread().getName()+"\tsendEmail");
}
}
/**
* Description:
* 可重入鎖(也叫做遞回鎖)
* 指的是同一執行緒外層函式獲得鎖后,內層遞回函式任然能獲取該鎖的代碼
* 在同一執行緒外外層方法獲取鎖的時候,在進入內層方法會自動獲取鎖
* 也就是說,執行緒可以進入任何一個它已經標記的鎖所同步的代碼塊
* **/
public class ReenterLockDemo {
/**
* t1 sendSms
* t1 sendEmail
* t2 sendSms
* t2 sendEmail
* @param args
*/
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(()->{
try {
phone.sendSms();
} catch (Exception e) {
e.printStackTrace();
}
},"t1").start();
new Thread(()->{
try {
phone.sendSms();
} catch (Exception e) {
e.printStackTrace();
}
},"t2").start();
}
}
- ④.
顯示鎖:(即lock)也有ReentrantLock這樣的可重入鎖
(注意:有多少個lock,就有多少個unlock,他們是配對使用的;如果多一個或者少一個會使得其他執行緒處于等待狀態)
class Phone2{
static ReentrantLock reentrantLock=new ReentrantLock();
public static void sendSms(){
reentrantLock.lock();
/*
//reentrantLock.lock();
注意有多少個lock,就有多少個unlock,他們是配對使用的
如果多了一個lock(),那么會出現執行緒B一直處于等待狀態
* */
reentrantLock.lock();
try {
System.out.println(Thread.currentThread().getName()+"\t"+"sendSms");
sendEmails();
}catch (Exception e){
e.printStackTrace();
}finally {
reentrantLock.unlock();
}
}
private static void sendEmails() {
reentrantLock.lock();
try {
System.out.println(Thread.currentThread().getName()+"\t"+"sendEmails...");
}catch (Exception e){
e.printStackTrace();
}finally {
reentrantLock.unlock();
}
}
}
public class ReentrantLockDemo {
public static void main(String[] args) {
Phone2 phone2=new Phone2();
new Thread(()->{phone2.sendSms();},"A").start();
new Thread(()->{phone2.sendSms();},"B").start();
}
}
②. 為什么要使用LockSupport
2>.為什么要使用LockSupport(先來了解下傳統的等待喚醒機制)
- ①. 3種讓執行緒等待喚醒的方法
- 使用Object中的wait()方法讓執行緒等待,使用Object中的notify方法喚醒執行緒
- 使用JUC包中Condition的await()方法讓執行緒等待,使用signal()方法喚醒執行緒
- LockSupport類可以阻塞當前執行緒以及喚醒指定被阻塞的執行緒
- ②. Object類中wait( )和notify( )實作執行緒的等待喚醒
- wait和notify方法必須要在同步塊或同步方法里且成對出現使用, wait和notify方法兩個都去掉同步代碼塊后看運行效果出現例外情況:
Exception in thread “A” Exception in thread “B”
java.lang.IllegalMonitorStateException - 先wait后notify才可以(如果先notify后wait會出現另一個執行緒一直處于等待狀態)
- synchronized是關鍵字屬于JVM層面,monitorenter(底層是通過monitor物件來完成,其實wait/notify等方法也依賴monitor物件只能在同步塊或方法中才能呼叫wait/notify等方法)
public class SynchronizedDemo {
//等待執行緒
public void waitThread(){
// 1.如果將synchronized (this){}注釋,會拋出例外,因為wait和notify一定要在同步塊或同步方法中
synchronized (this){
try {
System.out.println(Thread.currentThread().getName()+"\t"+"coming....");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(Thread.currentThread().getName()+"\t"+"end....");
}
}
//喚醒執行緒
public void notifyThread(){
synchronized (this){
System.out.println("喚醒A執行緒....");
notify();
}
}
public static void main(String[] args) {
SynchronizedDemo synchronizedDemo = new SynchronizedDemo();
new Thread(()->{
// 2.如果把下行這句代碼打開,先notify后wait,會出現A執行緒一直處于等待狀態
// try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) {e.printStackTrace();}
synchronizedDemo.waitThread();
},"A").start();
new Thread(()->{
synchronizedDemo.notifyThread();
},"B").start();
}
}
- ③. Condition介面中的await和signal方法實作執行緒等待和喚醒
(出現的問題和object中wait和notify一樣)
public class LockDemo {
static Object object=new Object();
public static void main(String[] args) {
Lock lock=new ReentrantLock();
Condition condition = lock.newCondition();
new Thread(()->{
//如果把下行這句代碼打開,先signal后await,會出現A執行緒一直處于等待狀態
//try { TimeUnit.SECONDS.sleep(3); } catch (InterruptedException e) {e.printStackTrace();}
lock.lock();
try {
System.out.println(Thread.currentThread().getName()+"\t"+"coming....");
condition.await();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
System.out.println(Thread.currentThread().getName()+"\t"+"END....");
},"A").start();
new Thread(()->{
lock.lock();
try {
System.out.println(Thread.currentThread().getName()+"\t"+"喚醒A執行緒****");
condition.signal();
}catch (Exception e){
e.printStackTrace();
}finally {
lock.unlock();
}
},"B").start();
}
}
③. JUC強大的三個工具類
3>. JUC強大的三個工具類 掌握
①. CountDownLatch(閉鎖)
-
①. CountDownLatch主要有兩個方法,當一個或多個執行緒呼叫await方法時,這些執行緒會阻塞
-
②. 其它執行緒呼叫countDown方法會將計數器減1(呼叫countDown方法的執行緒不會阻塞)
-
③. 計數器的值變為0時,因await方法阻塞的執行緒會被喚醒,繼續執行
//需求:要求6個執行緒都執行完了,mian執行緒最后執行
public class CountDownLatchDemo {
public static void main(String[] args) throws Exception{
CountDownLatch countDownLatch=new CountDownLatch(6);
for (int i = 1; i <=6; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"\t");
countDownLatch.countDown();
},i+"").start();
}
countDownLatch.await();
System.out.println(Thread.currentThread().getName()+"\t班長關門走人,main執行緒是班長");
}
}
- ④. 利用列舉減少if else的判斷
public enum CountryEnum {
one(1,"齊"),two(2,"楚"),three(3,"燕"),
four(4,"趙"),five(5,"魏"),six(6,"韓");
private Integer retCode;
private String retMessage;
private CountryEnum(Integer retCode,String retMessage){
this.retCode=retCode;
this.retMessage=retMessage;
}
public static CountryEnum getCountryEnum(Integer index){
CountryEnum[] countryEnums = CountryEnum.values();
for (CountryEnum countryEnum : countryEnums) {
if(countryEnum.getRetCode()==index){
return countryEnum;
}
}
return null;
}
public Integer getRetCode() {
return retCode;
}
public String getRetMessage() {
return retMessage;
}
}
/*
楚 **國,被滅
魏 **國,被滅
趙 **國,被滅
燕 **國,被滅
齊 **國,被滅
韓 **國,被滅
main **秦國一統江湖
* */
public class CountDownLatchDemo {
public static void main(String[] args) throws Exception{
CountDownLatch countDownLatch=new CountDownLatch(6);
for (int i = 1; i <=6; i++) {
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"\t"+"**國,被滅");
countDownLatch.countDown();
},CountryEnum.getCountryEnum(i).getRetMessage()).start();
}
countDownLatch.await();
System.out.println(Thread.currentThread().getName()+"\t"+"**秦國一統江湖");
}
}
②. CyclicBarrier
2>. CyclicBarrier
-
①. CyclicBarrier的字面意思是可回圈(Cyclic) 使用的屏障(barrier).它要做的事情是,讓一組執行緒到達一個屏障(也可以叫做同步點)時被阻塞,知道最后一個執行緒到達屏障時,屏障才會開門,所有被屏障攔截的執行緒才會繼續干活,執行緒進入屏障通過CyclicBarrier的await()方法
-
②. 代碼驗證:
//集齊7顆龍珠就能召喚神龍
public class CyclicBarrierDemo {
public static void main(String[] args) {
// public CyclicBarrier(int parties, Runnable barrierAction) {}
CyclicBarrier cyclicBarrier=new CyclicBarrier(7,()->{
System.out.println("召喚龍珠");
});
for (int i = 1; i <=7; i++) {
final int temp=i;
new Thread(()->{
System.out.println(Thread.currentThread().getName()+"\t收集到了第"+temp+"顆龍珠");
try {
cyclicBarrier.await();
} catch (InterruptedException e) {
e.printStackTrace();
} catch (BrokenBarrierException e) {
e.printStackTrace();
}
}).start();
}
}
}
③.Semaphore(信號量)
3>. Semaphore(信號量)
-
①. acquire(獲取) 當一個執行緒呼叫acquire操作時,它要么通過成功獲取信號量(信號量減1),要么一直等下去,直到有執行緒釋放信號量,或超時,
-
②. release(釋放)實際上會將信號量的值加1,然后喚醒等待的執行緒,
-
③. 信號量主要用于兩個目的,一個是用于多個共享資源的互斥使用,另一個用于并發執行緒數的控制,
-
④. 代碼驗證
public class SemaphoreDemo {
public static void main(String[] args) {
Semaphore semaphore=new Semaphore(3);
for (int i = 1; i <=6; i++) {
new Thread(()->{
try {
System.out.println(Thread.currentThread().getName()+"\t搶占了車位");
semaphore.acquire();
System.out.println(Thread.currentThread().getName()+"\t離開了車位");
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
semaphore.release();
}
},String.valueOf(i)).start();
}
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/187267.html
標籤:其他
上一篇:藍色版蘋果iPhone 12開箱上手視頻流出;谷歌回應司法部反壟斷訴訟:存在嚴重漏洞;?Git 2.29 穩定版發布|極客頭條
