死鎖
- 多個執行緒各自占有一些共享資源,并且互相等待其他執行緒占有的資源才能運行,而導致兩個或者多個執行緒都在等待對方釋放資源,都停止執行的情形,某一個同步塊同時擁有“兩個以上物件的鎖”時,就可能會發生“死鎖”的問題,
死鎖避免方法
-
產生死鎖的四個必要條件:
- 護持條件:一個資源每次只能被一個行程使用,
- 請求與保存條件:一個行程因請求資源而阻塞時,對已獲得的資源保持不放,
- 不剝奪條件:行程已獲得的資源,在未使用完之前,不能強行剝奪,
- 回圈等待條件:若干行程之間形成一種頭尾相接的回圈等待資源關系,
上面列出了死鎖的四個必要條件,我們只要想辦法破其中的任意一個或多個條件就可以避免死鎖的發生
死鎖與解鎖實體:
public class TextDemo {
public static void main(String[] args) {
bb b1=new bb(0,"喬丹");
bb b2=new bb(1,"林丹");
b1.start();
b2.start();
}
}
// 籃球
class basketball{
}
// 羽毛球
class badminton{
}
class bb extends Thread{
// 需要的資源只有一份,用static來保證只有一份
static basketball basketball = new basketball();
static badminton badminton = new badminton();
// 選擇
int choice;
// 使用球的人
String grilnmae;
bb(int choice,String grilnmae){
this.choice = choice;
this.grilnmae = grilnmae;
}
@Override
public void run() {
// 打球
try {
bb();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
private void bb() throws InterruptedException {
if(choice == 0){
synchronized (basketball){// 獲得籃球的鎖
System.out.println(this.grilnmae+"獲得了籃球");
Thread.sleep(1000);
synchronized (badminton){// 獲得羽毛球隊鎖
System.out.println(this.grilnmae+"獲得了羽毛球");
}
}
}else {
synchronized (badminton){// 獲得羽毛球的鎖
System.out.println(this.grilnmae+"獲得了羽毛球");
Thread.sleep(2000);
synchronized (basketball){// 獲得籃球隊鎖
System.out.println(this.grilnmae+"獲得了籃球");
}
}
}
}
}
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-hCgOed9r-1617976936604)(D:\學習\tupian\多執行緒\執行緒同步\ss.png)]](https://img.uj5u.com/2021/04/10/235075101202481.png)
這里已經產生死鎖了,程式不會再往下運行,就一直卡在這里,
因為程式畢竟不是人,只會執行,不會思考,代碼還需人打,
所以兩個執行緒分別報了對方的鎖,導致雙方僵持不下,程式無法運行
[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-MFdCJfSb-1617976936606)(D:\學習\tupian\多執行緒\執行緒同步\s2.png)]
-
解決方法如下:
點擊圖片 放大觀看
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-K2JDMsFW-1617976936607)(D:\學習\tupian\多執行緒\執行緒同步\s3.png)]](https://img.uj5u.com/2021/04/10/235075101202482.png)
![[外鏈圖片轉存失敗,源站可能有防盜鏈機制,建議將圖片保存下來直接上傳(img-kptxygaN-1617976936610)(D:\學習\tupian\多執行緒\執行緒同步\s4.png)]](https://img.uj5u.com/2021/04/10/235075101202483.png)
Lock(鎖)
- 從JDK5.0開始,Java提供了更強大的執行緒同步機制——通過顯式定義同步鎖物件來實作同步,同步鎖使用Lock物件充當
- java.util.concurrent.locks.Lock介面是控制多個執行緒對共享資源進行訪問的工具,鎖提供了對共享資源的獨占訪問,每次只能有一個執行緒對Lock物件加鎖,執行緒開始訪問共享資源之前應先獲得Lock物件
- ReentrantLock(可重入鎖)類實作了Lock,它擁有與synchronized相同的并發性和記憶體語意,在實作執行緒安全的控制中,比較長用的是ReentrantLock,可以顯示加鎖、釋放鎖,
synchronized 與 Lock 的對比
- Lock是顯式鎖(手動開啟和關閉鎖,別忘記關閉鎖)synchronized是隱式鎖,出了作用域自動釋放
- Lock只有代碼塊鎖,synchronized有代碼塊鎖和方法鎖
- 使用Lock鎖,JVM將花費較少的時間來調度執行緒,性能更好,并且具有更好的擴展性(提供更多的子類)
- 優先使用順序:
- Lock > 同步代碼塊(已經進入了方法體,分配了相應資源)> 同步方法(在方法體之外)
實體:
public class LockDemo {
public static void main(String[] args) {
TestLock t = new TestLock();
new Thread(t).start();
new Thread(t).start();
new Thread(t).start();
}
}
class TestLock implements Runnable{
int ticketNums = 10;
// 定義lock鎖
private final ReentrantLock lock = new ReentrantLock();
@Override
public void run() {
while (true){
try {
// 加鎖
lock.lock();
if (ticketNums > 0){
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(ticketNums--);
}else{
break;
}
}finally {
// 解鎖
lock.unlock();
}
}
}
}
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/274523.html
標籤:其他
上一篇:c語言撰寫圖書管理系統例子
下一篇:JavaScript的構成
