最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java死鎖和活鎖的聯(lián)系及說明

 更新時間:2025年05月13日 10:22:47   作者:找不到、了  
這篇文章主要介紹了Java死鎖和活鎖的聯(lián)系及說明,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教

本章還是重點介紹下java開發(fā)過程中,會出現(xiàn)的鎖。

在多線程編程中,死鎖(Deadlock)活鎖(Livelock)都是線程間協(xié)調(diào)不當(dāng)導(dǎo)致的執(zhí)行困境,但二者的表現(xiàn)和機制有顯著區(qū)別。

并發(fā)編程中的常見問題

├── 活鎖 (Livelock)
│   ├── 定義:兩個或多個進程或線程相互之間不斷嘗試執(zhí)行某個操作,但由于彼此的影響,這些操作都無法成功完成
│   ├── 特點:系統(tǒng)不會崩潰,但也不會取得任何進展
│   ├── 示例:線程A和線程B互相等待對方改變標(biāo)志

├── 饑餓 (Starvation)
│   ├── 定義:某個線程或進程由于資源競爭或調(diào)度策略的原因,長時間無法獲得必要的資源,導(dǎo)致其無法執(zhí)行
│   ├── 特點:某些線程或進程始終得不到執(zhí)行的機會
│   ├── 示例:低優(yōu)先級任務(wù)始終無法執(zhí)行

├── 無鎖 (Lock-Free)
│   ├── 定義:不使用傳統(tǒng)的互斥鎖,而是使用原子操作和內(nèi)存模型來實現(xiàn)線程安全
│   ├── 特點:提高并發(fā)性能,減少鎖的競爭
│   ├── 示例:使用 AtomicInteger 實現(xiàn)線程安全的計數(shù)器

└── 死鎖 (Deadlock)
    ├── 定義:兩個或多個進程或線程在執(zhí)行過程中,因爭奪資源而造成的一種相互等待的現(xiàn)象
    ├── 特點:系統(tǒng)陷入停滯狀態(tài),無法繼續(xù)執(zhí)行
    ├── 示例:兩個線程互相等待對方持有的鎖

1、死鎖

1、產(chǎn)生原因

滿足下面四個必要條件,則會產(chǎn)生死鎖現(xiàn)象。

1、互斥條件

線程對所分配到的資源進行排他性使用,即在一段時間內(nèi)某資源只由一個線程占用。如果此時還有其它線程請求該資源,則請求者只能等待,直至占有資源的線程用畢釋放。

2、請求和保持條件

線程已經(jīng)保持了至少一個資源,但又提出了新的資源請求,而該資源已被其它線程占有,此時請求線程阻塞,但又對自己已獲得的其它資源保持不放。

3、不剝奪條件

線程已獲得的資源,在未使用完之前,不能被剝奪,只能在使用完時由自己釋放。

4、循環(huán)等待條件

在發(fā)生死鎖時,必然存在一個線程 —— 資源的環(huán)形鏈,即線程集合 {T0,T1,T2,???,Tn} 中的 T0 正在等待一個 T1 占用的資源;T1 正在等待 T2 占用的資源,……,Tn 正在等待已被 T0 占用的資源。

代碼示例:

class DeadlockExample {
    private static final Object resource1 = new Object();
    private static final Object resource2 = new Object();

    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            synchronized (resource1) {
                System.out.println("Thread 1: Holding resource 1...");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Thread 1: Waiting for resource 2...");
                synchronized (resource2) {
                    System.out.println("Thread 1: Holding resource 1 and 2...");
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            synchronized (resource2) {
                System.out.println("Thread 2: Holding resource 2...");
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("Thread 2: Waiting for resource 1...");
                synchronized (resource1) {
                    System.out.println("Thread 2: Holding resource 1 and 2...");
                }
            }
        });

        thread1.start();
        thread2.start();
    }
}

代碼解釋

  • resource1resource2 是兩個共享資源。
  • thread1 先獲取 resource1,然后嘗試獲取 resource2。
  • thread2 先獲取 resource2,然后嘗試獲取 resource1。
  • 由于 thread1thread2 都在等待對方釋放資源,從而導(dǎo)致死鎖。

由上面可知,死鎖的四個條件均滿足。

2、死鎖場景

3、解決方案

3.1. 預(yù)防

預(yù)防死鎖

通過破壞產(chǎn)生死鎖的四個必要條件中的一個或幾個來預(yù)防死鎖的發(fā)生。例如,一次性獲取所有需要的資源,避免請求和保持條件;或者允許資源被剝奪。

避免死鎖

在資源分配過程中,通過算法來判斷是否會發(fā)生死鎖,只有在不會發(fā)生死鎖的情況下才進行資源分配。例如,銀行家算法。

1. 順序獲取鎖

方案:確保所有線程以相同的順序獲取鎖,避免不同的鎖獲取順序(最有效方案)。

public class DeadlockSolution1 {
    private static final Object lock1 = new Object();
    private static final Object lock2 = new Object();

    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            synchronized (lock1) {
                System.out.println("Thread1 acquired lock1");
                // 添加小延遲,增加死鎖概率
                try { Thread.sleep(100); } catch (InterruptedException e) {}
                
                synchronized (lock2) {
                    System.out.println("Thread1 acquired lock2");
                }
            }
        });

        Thread thread2 = new Thread(() -> {
            synchronized (lock1) {  // 改為先獲取lock1,與thread1順序一致
                System.out.println("Thread2 acquired lock1");
                try { Thread.sleep(100); } catch (InterruptedException e) {}
                
                synchronized (lock2) {
                    System.out.println("Thread2 acquired lock2");
                }
            }
        });

        thread1.start();
        thread2.start();
    }
}

2. 使用 tryLock (帶超時)

方案:使用 ReentrantLocktryLock() 方法,避免無限期等待,可以增加回退方案,并且超時情況下線程會釋放掉鎖。

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class DeadlockSolution2 {
    private static final Lock lock1 = new ReentrantLock();
    private static final Lock lock2 = new ReentrantLock();

    public static void main(String[] args) {
        Thread thread1 = new Thread(() -> {
            try {
                if (lock1.tryLock(500, TimeUnit.MILLISECONDS)) {
                    System.out.println("Thread1 acquired lock1");
                    try { Thread.sleep(100); } catch (InterruptedException e) {}
                    
                    if (lock2.tryLock(500, TimeUnit.MILLISECONDS)) {
                        System.out.println("Thread1 acquired lock2");
                        lock2.unlock();
                    } else {
                        System.out.println("Thread1 failed to acquire lock2");
                    }
                    lock1.unlock();
                } else {
                    System.out.println("Thread1 failed to acquire lock1");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        Thread thread2 = new Thread(() -> {
            try {
                if (lock2.tryLock(500, TimeUnit.MILLISECONDS)) {
                    System.out.println("Thread2 acquired lock2");
                    try { Thread.sleep(100); } catch (InterruptedException e) {}
                    
                    if (lock1.tryLock(500, TimeUnit.MILLISECONDS)) {
                        System.out.println("Thread2 acquired lock1");
                        lock1.unlock();
                    } else {
                        System.out.println("Thread2 failed to acquire lock1");
                    }
                    lock2.unlock();
                } else {
                    System.out.println("Thread2 failed to acquire lock2");
                }
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        });

        thread1.start();
        thread2.start();
    }
}

3. Phaser

方案:使用 java.util.concurrent 包中的高級工具類替代顯式鎖。

import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.Phaser;

public class DeadlockSolution4 {
    public static void main(String[] args) {
        ExecutorService executor = Executors.newFixedThreadPool(2);
        Phaser phaser = new Phaser(2); // 使用Phaser協(xié)調(diào)線程
        
        executor.submit(() -> {
            System.out.println("Task1 started");
            phaser.arriveAndAwaitAdvance(); // 等待其他線程
            System.out.println("Task1 completed");
        });
        
        executor.submit(() -> {
            System.out.println("Task2 started");
            phaser.arriveAndAwaitAdvance(); // 等待其他線程
            System.out.println("Task2 completed");
        });
        
        executor.shutdown();
    }
}

4. 銀行家算法

  • 安全狀態(tài):系統(tǒng)能按某種順序為所有進程分配資源,使它們都能順利完成
  • 不安全狀態(tài):系統(tǒng)可能進入死鎖的狀態(tài)

四種數(shù)據(jù)結(jié)構(gòu)

  • Available:可用資源向量
  • Max:每個進程最大需求矩陣
  • Allocation:已分配資源矩陣
  • Need:需求矩陣(Need = Max - Allocation)

實現(xiàn)步驟:

1. 安全狀態(tài)檢查算法

boolean isSafeState() {
    // 1. 初始化
    int[] work = Arrays.copyOf(Available, Available.length);
    boolean[] finish = new boolean[processCount];
    Arrays.fill(finish, false);
    
    // 2. 尋找可滿足的進程
    int count = 0;
    while (count < processCount) {
        boolean found = false;
        for (int i = 0; i < processCount; i++) {
            if (!finish[i] && checkNeedLessThanWork(i, work)) {
                // 3. 假設(shè)進程i釋放資源
                for (int j = 0; j < resourceTypes; j++) {
                    work[j] += Allocation[i][j];
                }
                finish[i] = true;
                found = true;
                count++;
            }
        }
        if (!found) break; // 沒有找到可滿足的進程
    }
    
    // 4. 檢查是否所有進程都能完成
    return count == processCount;
}

boolean checkNeedLessThanWork(int process, int[] work) {
    for (int i = 0; i < resourceTypes; i++) {
        if (Need[process][i] > work[i]) {
            return false;
        }
    }
    return true;
}

2. 資源請求算法

boolean requestResources(int process, int[] request) {
    // 1. 檢查請求是否超過聲明需求
    for (int i = 0; i < resourceTypes; i++) {
        if (request[i] > Need[process][i]) {
            return false;
        }
    }
    
    // 2. 檢查系統(tǒng)是否有足夠資源
    for (int i = 0; i < resourceTypes; i++) {
        if (request[i] > Available[i]) {
            return false;
        }
    }
    
    // 3. 嘗試分配
    for (int i = 0; i < resourceTypes; i++) {
        Available[i] -= request[i];
        Allocation[process][i] += request[i];
        Need[process][i] -= request[i];
    }
    
    // 4. 檢查安全性
    if (isSafeState()) {
        return true;
    } else {
        // 回滾分配
        for (int i = 0; i < resourceTypes; i++) {
            Available[i] += request[i];
            Allocation[process][i] -= request[i];
            Need[process][i] += request[i];
        }
        return false;
    }
}

銀行家算法通過以下機制預(yù)防死鎖:

事前預(yù)防:在資源分配前進行安全性檢查

  • 只有當(dāng)分配后系統(tǒng)仍處于安全狀態(tài)時才允許分配
  • 避免了系統(tǒng)進入可能導(dǎo)致死鎖的狀態(tài)

破壞死鎖必要條件

  • 破壞"循環(huán)等待"條件:通過確保至少有一個進程總能獲得所需資源
  • 破壞"占有并等待"條件:通過要求進程一次性聲明最大需求

動態(tài)決策

  • 每次資源請求都重新評估系統(tǒng)安全性
  • 比靜態(tài)預(yù)防策略更靈活

3.2. 檢測

檢測死鎖

  • 通過一定的算法來檢測系統(tǒng)中是否存在死鎖。
  • 例如,資源分配圖算法。

解除死鎖

  • 當(dāng)檢測到死鎖后,需要采取措施來解除死鎖。
  • 例如,剝奪某個線程的資源,或者終止某個線程。

2、活鎖

1、介紹

活鎖是指線程不斷改變狀態(tài)來響應(yīng)對方,但整體任務(wù)無法推進。

線程未阻塞,仍在不斷嘗試執(zhí)行操作,但因相互干擾陷入無效循環(huán),CPU 利用率不為 0(線程在執(zhí)行無意義的重試)。

2、場景

  • 兩個線程(Worker1Worker2)需要同時獲取兩把鎖(lock1lock2)才能工作。
  • 如果某個線程發(fā)現(xiàn)鎖被占用,它會主動釋放自己的鎖并重試(而不是阻塞等待)。
  • 由于兩個線程同時讓步,導(dǎo)致它們無限循環(huán)地釋放和重試,但永遠無法完成任務(wù)。

線程的調(diào)度由于不停切換,也會導(dǎo)致。

代碼示例:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class LivelockExample {
    private final Lock lock1 = new ReentrantLock();
    private final Lock lock2 = new ReentrantLock();

    public void worker1() {
        while (true) {
            lock1.lock();
            System.out.println("Worker1 獲取 lock1");
            
            // 嘗試獲取 lock2,如果失敗就釋放 lock1 并重試
            if (lock2.tryLock()) {
                System.out.println("Worker1 獲取 lock2,完成任務(wù)");
                lock2.unlock();
                lock1.unlock();
                break;
            } else {
                System.out.println("Worker1 無法獲取 lock2,釋放 lock1 并重試");
                lock1.unlock();
            }
            
            // 短暫休眠,避免 CPU 100%
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }

    public void worker2() {
        while (true) {
            lock2.lock();
            System.out.println("Worker2 獲取 lock2");
            
            // 嘗試獲取 lock1,如果失敗就釋放 lock2 并重試
            if (lock1.tryLock()) {
                System.out.println("Worker2 獲取 lock1,完成任務(wù)");
                lock1.unlock();
                lock2.unlock();
                break;
            } else {
                System.out.println("Worker2 無法獲取 lock1,釋放 lock2 并重試");
                lock2.unlock();
            }
            
            // 短暫休眠,避免 CPU 100%
            try {
                Thread.sleep(10);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }

    public static void main(String[] args) {
        LivelockExample example = new LivelockExample();
        
        Thread t1 = new Thread(example::worker1);
        Thread t2 = new Thread(example::worker2);
        
        t1.start();
        t2.start();
    }
}

以下是可能的執(zhí)行順序:

Worker1 獲取 lock1
Worker2 獲取 lock2
Worker1 無法獲取 lock2,釋放 lock1 并重試
Worker2 無法獲取 lock1,釋放 lock2 并重試
Worker1 獲取 lock1
Worker2 獲取 lock2
Worker1 無法獲取 lock2,釋放 lock1 并重試
Worker2 無法獲取 lock1,釋放 lock2 并重試
...(無限循環(huán))

現(xiàn)象

  • 兩個線程都在運行(沒有阻塞,不像死鎖)。
  • 它們不斷嘗試獲取對方的鎖,但發(fā)現(xiàn)鎖被占用后主動釋放自己的鎖并重試。
  • 由于同時讓步,導(dǎo)致無限循環(huán),任務(wù)無法完成。

3、處理方案

1. 引入隨機退避

示例:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import java.util.Random;

public class RandomBackoffSolution {
    private final Lock lock1 = new ReentrantLock();
    private final Lock lock2 = new ReentrantLock();
    private final Random random = new Random();

    public void worker1() {
        while (true) {
            lock1.lock();
            System.out.println("Worker1 獲取 lock1");
            
            try {
                // 引入隨機退避
                Thread.sleep(random.nextInt(100)); // 隨機等待0-99ms
                
                if (lock2.tryLock()) {
                    try {
                        System.out.println("Worker1 獲取 lock2,完成任務(wù)");
                        return; // 成功完成任務(wù)
                    } finally {
                        lock2.unlock();
                    }
                } else {
                    System.out.println("Worker1 無法獲取 lock2,釋放 lock1 并重試");
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } finally {
                lock1.unlock();
            }
            
            // 再次隨機退避
            try {
                Thread.sleep(random.nextInt(100));
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }

    public void worker2() {
        while (true) {
            lock2.lock();
            System.out.println("Worker2 獲取 lock2");
            
            try {
                // 引入隨機退避
                Thread.sleep(random.nextInt(100)); // 隨機等待0-99ms
                
                if (lock1.tryLock()) {
                    try {
                        System.out.println("Worker2 獲取 lock1,完成任務(wù)");
                        return; // 成功完成任務(wù)
                    } finally {
                        lock1.unlock();
                    }
                } else {
                    System.out.println("Worker2 無法獲取 lock1,釋放 lock2 并重試");
                }
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            } finally {
                lock2.unlock();
            }
            
            // 再次隨機退避
            try {
                Thread.sleep(random.nextInt(100));
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }

    public static void main(String[] args) {
        RandomBackoffSolution solution = new RandomBackoffSolution();
        
        new Thread(solution::worker1).start();
        new Thread(solution::worker2).start();
    }
}

2. 限制重試次數(shù)

示例:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class RetryLimitSolution {
    private final Lock lock1 = new ReentrantLock();
    private final Lock lock2 = new ReentrantLock();
    private static final int MAX_RETRIES = 5;

    public void worker1() {
        int retryCount = 0;
        while (retryCount < MAX_RETRIES) {
            retryCount++;
            lock1.lock();
            System.out.println("Worker1 獲取 lock1 (嘗試 " + retryCount + "/" + MAX_RETRIES + ")");
            
            try {
                if (lock2.tryLock()) {
                    try {
                        System.out.println("Worker1 獲取 lock2,完成任務(wù)");
                        return;
                    } finally {
                        lock2.unlock();
                    }
                } else {
                    System.out.println("Worker1 無法獲取 lock2,釋放 lock1 并重試");
                }
            } finally {
                lock1.unlock();
            }
            
            try {
                Thread.sleep(100); // 固定等待時間
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        System.out.println("Worker1 達到最大重試次數(shù),放棄任務(wù)");
    }

    public void worker2() {
        int retryCount = 0;
        while (retryCount < MAX_RETRIES) {
            retryCount++;
            lock2.lock();
            System.out.println("Worker2 獲取 lock2 (嘗試 " + retryCount + "/" + MAX_RETRIES + ")");
            
            try {
                if (lock1.tryLock()) {
                    try {
                        System.out.println("Worker2 獲取 lock1,完成任務(wù)");
                        return;
                    } finally {
                        lock1.unlock();
                    }
                } else {
                    System.out.println("Worker2 無法獲取 lock1,釋放 lock2 并重試");
                }
            } finally {
                lock2.unlock();
            }
            
            try {
                Thread.sleep(100); // 固定等待時間
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
        System.out.println("Worker2 達到最大重試次數(shù),放棄任務(wù)");
    }

    public static void main(String[] args) {
        RetryLimitSolution solution = new RetryLimitSolution();
        
        new Thread(solution::worker1).start();
        new Thread(solution::worker2).start();
    }
}

3. 調(diào)整鎖獲取順序

這個方案比較推薦。示例:

import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class OrderedLockSolution {
    private final Lock lock1 = new ReentrantLock();
    private final Lock lock2 = new ReentrantLock();

    // 定義全局鎖獲取順序
    private static final Object lockOrder = new Object();

    public void worker1() {
        while (true) {
            // 按照固定順序獲取鎖
            synchronized (lockOrder) {
                lock1.lock();
                System.out.println("Worker1 獲取 lock1");
                
                try {
                    if (lock2.tryLock()) {
                        try {
                            System.out.println("Worker1 獲取 lock2,完成任務(wù)");
                            return;
                        } finally {
                            lock2.unlock();
                        }
                    } else {
                        System.out.println("Worker1 無法獲取 lock2,釋放 lock1 并重試");
                    }
                } finally {
                    lock1.unlock();
                }
            }
            
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }

    public void worker2() {
        while (true) {
            // 按照相同順序獲取鎖
            synchronized (lockOrder) {
                lock1.lock();
                System.out.println("Worker2 獲取 lock1");
                
                try {
                    if (lock2.tryLock()) {
                        try {
                            System.out.println("Worker2 獲取 lock2,完成任務(wù)");
                            return;
                        } finally {
                            lock2.unlock();
                        }
                    } else {
                        System.out.println("Worker2 無法獲取 lock2,釋放 lock1 并重試");
                    }
                } finally {
                    lock1.unlock();
                }
            }
            
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                Thread.currentThread().interrupt();
            }
        }
    }

    public static void main(String[] args) {
        OrderedLockSolution solution = new OrderedLockSolution();
        
        new Thread(solution::worker1).start();
        new Thread(solution::worker2).start();
    }
}

3、聯(lián)系

總結(jié)

理解死鎖和活鎖的區(qū)別與聯(lián)系,有助于開發(fā)出更健壯的并發(fā)程序。在實際開發(fā)中,應(yīng)當(dāng)優(yōu)先考慮使用java.util.concurrent包提供的高級并發(fā)工具,而非直接使用低級的同步機制。

以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

最新評論

静海县| 松江区| 保德县| 铁岭市| 科技| 吉水县| 大埔区| 霍林郭勒市| 日照市| 霍邱县| 财经| 巴楚县| 孟村| 长泰县| 阿拉善左旗| 新乡市| 新巴尔虎左旗| 临潭县| 湖南省| 怀仁县| 淄博市| 德保县| 大新县| 庆云县| 黑水县| 西吉县| 柳州市| 石棉县| 林州市| 霸州市| 鲜城| 东莞市| 石城县| 新河县| 高雄县| 四川省| 昂仁县| 光山县| 土默特左旗| 时尚| 包头市|