日日操夜夜添-日日操影院-日日草夜夜操-日日干干-精品一区二区三区波多野结衣-精品一区二区三区高清免费不卡

公告:魔扣目錄網(wǎng)為廣大站長提供免費(fèi)收錄網(wǎng)站服務(wù),提交前請做好本站友鏈:【 網(wǎng)站目錄:http://www.ylptlb.cn 】, 免友鏈快審服務(wù)(50元/站),

點(diǎn)擊這里在線咨詢客服
新站提交
  • 網(wǎng)站:51998
  • 待審:31
  • 小程序:12
  • 文章:1030137
  • 會員:747

JAVA線程死鎖

Java線程死鎖發(fā)生的常見行為是雙方互相持有對方需要的鎖:即兩個(gè)或多個(gè)線程在等待彼此持有的鎖,導(dǎo)致所有線程都無法繼續(xù)執(zhí)行下去。這種情況通常會產(chǎn)生一個(gè)循環(huán)等待的場景。

舉例代碼:

public class DeadlockExample {
    private static Object lockA = new Object();
    private static Object lockB = new Object();

    public static void main(String[] args) {
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lockA) {
                    System.out.println("Thread 1 acquired lock A");
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (lockB) {
                        System.out.println("Thread 1 acquired lock B");
                    }
                }
            }
        });

        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                synchronized (lockB) {
                    System.out.println("Thread 2 acquired lock B");
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    synchronized (lockA) {
                        System.out.println("Thread 2 acquired lock A");
                    }
                }
            }
        });

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

為避免死鎖,可以采取以下措施:

 

  1. 避免嵌套鎖
  2. 使用同步塊代替同步方法
  3. 按照固定順序獲取鎖
  4. 可以使用Lock對象代替synchronized關(guān)鍵字
  5. 使用Semaphore避免死鎖
  6. 使用ThreadLocal為每個(gè)線程提供獨(dú)立的變量副本,避免多個(gè)線程之間共享變量導(dǎo)致的死鎖問題
  7. 避免長時(shí)間持有鎖,盡可能減少持有鎖的時(shí)間
  8. 使用非阻塞算法或無鎖算法

修改上述代碼

使用ReentrantLock

使用ReentrantLock時(shí),需要將所有涉及到共享資源的代碼放在lock()和unlock()方法之間,才能保證線程安全。在之前的代碼示例中,if代碼塊沒有被包括在lock()和unlock()方法之間,因此不具備線程安全性。

 

以下是修改后的示例代碼:

public class DeadlockExample {
    private static final ReentrantLock lockA = new ReentrantLock();
    private static final ReentrantLock lockB = new ReentrantLock();

    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    lockA.lock();
                    System.out.println("Thread 1 acquired lock A");
                    Thread.sleep(100);
                    if (lockB.tryLock(100, TimeUnit.MILLISECONDS)) {
                        System.out.println("Thread 1 acquired lock B");
                        Thread.sleep(100);
                    } else {
                        System.out.println("Thread 1 failed to acquire lock B, aborting");
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    if (lockB.isHeldByCurrentThread()) {
                        lockB.unlock();
                        System.out.println("Thread 1 released lock B");
                    }
                    lockA.unlock();
                    System.out.println("Thread 1 released lock A");
                }
            }
        });

        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    lockB.lock();
                    System.out.println("Thread 2 acquired lock B");
                    Thread.sleep(100);
                    if (lockA.tryLock(100, TimeUnit.MILLISECONDS)) {
                        System.out.println("Thread 2 acquired lock A");
                        Thread.sleep(100);
                    } else {
                        System.out.println("Thread 2 failed to acquire lock A, aborting");
                    }
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    if (lockA.isHeldByCurrentThread()) {
                        lockA.unlock();
                        System.out.println("Thread 2 released lock A");
                    }
                    lockB.unlock();
                    System.out.println("Thread 2 released lock B");
                }
            }
        });

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

        thread1.join();
        thread2.join();
    }
}

以上代碼中,在每個(gè)線程的run方法中,我們依次獲取兩把鎖,并在獲取到鎖之后進(jìn)行相應(yīng)的操作。在釋放鎖時(shí),需要先判斷當(dāng)前線程是否持有該鎖,如果是,則釋放該鎖,并打印相應(yīng)的信息。

這樣修改后,就能保證線程安全和避免死鎖的問題了。

使用Semaphore

以下是修改后的示例代碼:

 

public class DeadlockExample {
    private static final Semaphore semaphoreA = new Semaphore(1);
    private static final Semaphore semaphoreB = new Semaphore(1);

    public static void main(String[] args) throws InterruptedException {
        Thread thread1 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    semaphoreA.acquire();
                    System.out.println("Thread 1 acquired semaphore A");
                    Thread.sleep(100);

                    while (!semaphoreB.tryAcquire()) {
                        semaphoreA.release();
                        System.out.println("Thread 1 released semaphore A and waiting for semaphore B");
                        semaphoreA.acquire();
                        System.out.println("Thread 1 acquired semaphore A again");
                    }

                    System.out.println("Thread 1 acquired semaphore B");
                    Thread.sleep(100);

                    semaphoreB.release();
                    System.out.println("Thread 1 released semaphore B");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    semaphoreA.release();
                    System.out.println("Thread 1 released semaphore A");
                }
            }
        });

        Thread thread2 = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    semaphoreB.acquire();
                    System.out.println("Thread 2 acquired semaphore B");
                    Thread.sleep(100);

                    while (!semaphoreA.tryAcquire()) {
                        semaphoreB.release();
                        System.out.println("Thread 2 released semaphore B and waiting for semaphore A");
                        semaphoreB.acquire();
                        System.out.println("Thread 2 acquired semaphore B again");
                    }

                    System.out.println("Thread 2 acquired semaphore A");
                    Thread.sleep(100);

                    semaphoreA.release();
                    System.out.println("Thread 2 released semaphore A");
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } finally {
                    semaphoreB.release();
                    System.out.println("Thread 2 released semaphore B");
                }
            }
        });

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

        thread1.join();
        thread2.join();
    }
}

以上代碼中,如果全部使用acquire(),那么在當(dāng)前線程獲取到第一個(gè)資源后,如果無法獲取第二個(gè)資源,就會釋放第一個(gè)資源,并進(jìn)入等待狀態(tài)。然而,由于此時(shí)其他線程可能已經(jīng)獲取了第一個(gè)資源并在等待第二個(gè)資源,因此當(dāng)前線程可能永遠(yuǎn)無法獲取到第二個(gè)資源,從而導(dǎo)致死鎖的發(fā)生。

 

為了避免這種情況,可以使用tryAcquire()方法來嘗試獲取第二個(gè)資源,如果無法獲取,則先釋放第一個(gè)資源再進(jìn)行等待。

這樣修改后,就能保證線程安全和避免死鎖的問題了。

Java線程饑餓

Java中線程饑餓(Thread Starvation)是指某個(gè)或某些線程無法獲得所需的資源,從而無法繼續(xù)執(zhí)行下去,導(dǎo)致程序出現(xiàn)假死等異常情況。

 

舉個(gè)例子,如果一個(gè)高優(yōu)先級的線程一直占用某個(gè)共享資源,并且低優(yōu)先級的線程總是無法獲取該資源,那么這些低優(yōu)先級的線程就會一直處于等待狀態(tài),無法執(zhí)行下去,從而導(dǎo)致線程饑餓的發(fā)生。

另外,線程饑餓也可能發(fā)生在多個(gè)線程競爭同一資源時(shí),如果某些線程總是能夠比其他線程更快地獲取到該資源,那么其他線程就會一直處于等待狀態(tài),無法及時(shí)完成任務(wù),從而導(dǎo)致線程饑餓的發(fā)生。

為避免線程饑餓的發(fā)生,可以采取以下措施:

  1. 合理設(shè)計(jì)線程優(yōu)先級,盡量保證每個(gè)線程都能有機(jī)會獲取到所需的資源。
  2. 使用公平鎖來保證資源的公平分配,避免某個(gè)線程長期占用某個(gè)資源。
  3. 盡量減少線程等待的時(shí)間,例如使用超時(shí)機(jī)制、避免死鎖等方式來盡早釋放資源,讓其他線程有機(jī)會獲取到資源。
  4. 對于一些不必要占用大量資源的線程,可以將其設(shè)置為低優(yōu)先級或者使用線程池等方式來限制其數(shù)量,從而避免線程饑餓的發(fā)生。

總之,在編寫多線程程序時(shí)需要注意線程饑餓問題,并采取相應(yīng)措施來保證程序的正常執(zhí)行。

以下是一個(gè)簡單的代碼示例,模擬了線程饑餓的情況。

 

public class ThreadStarvationExample {
    private static final Object lock = new Object();

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            final int index = i;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (lock) {
                        System.out.println("Thread " + index + " acquired lock");
                        try {
                            // 模擬某些線程需要占用鎖較長時(shí)間
                            if (index == 2 || index == 3) {
                                Thread.sleep(5000);
                            } else {
                                Thread.sleep(1000);
                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        System.out.println("Thread " + index + " released lock");
                    }
                }
            }).start();
        }
    }
}

以上代碼中,我們創(chuàng)建了10個(gè)線程,并對它們共享的一個(gè)鎖進(jìn)行競爭。其中,第2個(gè)線程和第3個(gè)線程分別需要占用鎖5秒鐘和其他線程相比更久的時(shí)間。

如果運(yùn)行以上代碼,我們可能會發(fā)現(xiàn)第2個(gè)線程和第3個(gè)線程總是優(yōu)先獲得鎖,而其他線程則會等待較長時(shí)間才能獲取到鎖,從而導(dǎo)致這些線程在整個(gè)程序執(zhí)行期間都無法正常執(zhí)行下去,出現(xiàn)線程饑餓的情況。

為避免線程饑餓的發(fā)生,我們可以對占用鎖時(shí)間較長的線程做出調(diào)整,例如將它們設(shè)置為低優(yōu)先級或者減少其持有鎖的時(shí)間等措施。

另外,我們還可以使用公平鎖來保證資源的公平分配,避免某個(gè)線程長期占用某個(gè)資源。以下是修改后的代碼示例:

 

public class ThreadStarvationExample {
    private static final ReentrantLock lock = new ReentrantLock(true);

    public static void main(String[] args) {
        for (int i = 0; i < 10; i++) {
            final int index = i;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    synchronized (lock) {
                        System.out.println("Thread " + index + " acquired lock");
                        try {
                            if (index == 2 || index == 3) {
                                // 將占用鎖時(shí)間較長的線程設(shè)置為低優(yōu)先級
                                Thread.currentThread().setPriority(Thread.MIN_PRIORITY);
                                Thread.sleep(5000);
                            } else {
                                Thread.sleep(1000);
                            }
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        } finally {
                            // 減少持有鎖的時(shí)間,增加其他線程獲取鎖的機(jī)會
                            try {
                                Thread.sleep(100);
                            } catch (InterruptedException e) {
                                e.printStackTrace();
                            }
                            System.out.println("Thread " + index + " released lock");
                        }
                    }
                }
            }).start();
        }
    }
}

分享到:
標(biāo)簽:線程
用戶無頭像

網(wǎng)友整理

注冊時(shí)間:

網(wǎng)站:5 個(gè)   小程序:0 個(gè)  文章:12 篇

  • 51998

    網(wǎng)站

  • 12

    小程序

  • 1030137

    文章

  • 747

    會員

趕快注冊賬號,推廣您的網(wǎng)站吧!
最新入駐小程序

數(shù)獨(dú)大挑戰(zhàn)2018-06-03

數(shù)獨(dú)一種數(shù)學(xué)游戲,玩家需要根據(jù)9

答題星2018-06-03

您可以通過答題星輕松地創(chuàng)建試卷

全階人生考試2018-06-03

各種考試題,題庫,初中,高中,大學(xué)四六

運(yùn)動步數(shù)有氧達(dá)人2018-06-03

記錄運(yùn)動步數(shù),積累氧氣值。還可偷

每日養(yǎng)生app2018-06-03

每日養(yǎng)生,天天健康

體育訓(xùn)練成績評定2018-06-03

通用課目體育訓(xùn)練成績評定