激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - Java并發編程加鎖導致的活躍性問題詳解方案

Java并發編程加鎖導致的活躍性問題詳解方案

2022-03-06 00:51該用戶快成仙了 Java教程

所謂并發編程是指在一臺處理器上"同時"處理多個任務。并發是在同一實體上的多個事件。多個事件在同一時間間隔發生,所以編寫正確的程序很難,而編寫正確的并發程序則難上加難

我們主要處理鎖帶來的問題.
首先就是最出名的死鎖

死鎖(Deadlock)

什么是死鎖

Java并發編程加鎖導致的活躍性問題詳解方案

死鎖是當線程進入無限期等待狀態時發生的情況,因為所請求的鎖被另一個線程持有,而另一個線程又等待第一個線程持有的另一個鎖 導致互相等待。總結:多個線程互相等待對方釋放鎖。

例如在現實中的十字路口,鎖就像紅綠燈指示器,一旦鎖壞了,就會導致交通癱瘓。
那么該如何避免這個問題呢

死鎖的解決和預防

1.超時釋放鎖

>顧名思義,這種避免死鎖的方式是在嘗試獲取鎖的時候加一個超時時間,這就意味著,如果一個線程在獲取鎖的門口等待太久這個線程就會放棄這次請求,退還并釋放所有已經獲得的鎖,再在等待一段隨機時間后再次嘗試,這段時間其他的線程伙伴可以去嘗試拿鎖.

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public interface Lock {
    //自定義異常類
    public static class TimeOutException extends Exception{
        public TimeOutException(String message){
            super(message);
        }
    }
    //無超時鎖,可以被打斷
    void lock() throws  InterruptedException;
    //超時鎖,可以被打斷
    void lock(long molls) throws InterruptedException,TimeOutException;
    //解鎖
    void unlock();
    //獲取當前等待的線程
    Collection<Thread> getBlockedThread();
    //獲取當前阻塞的線程數目
    int getBlockSize();
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
public class BooleanLock  implements Lock{
    private boolean initValue;
    private Thread currenThread;
    public BooleanLock(){
        this.initValue = false;
    }
    private Collection<Thread> blockThreadCollection = new ArrayList<>();
 
    @Override
    public synchronized void lock() throws InterruptedException {
        while (initValue){
            blockThreadCollection.add(Thread.currentThread());
            this.wait();
        }
        //表明此時正在用,別人進來就要鎖住
        this.initValue = true;
        currenThread = Thread.currentThread();
        blockThreadCollection.remove(Thread.currentThread());//從集合中刪除
    }
 
    @Override
    public synchronized void lock(long mills) throws InterruptedException, TimeOutException {
        if (mills<=0){
            lock();
        }else {
            long hasRemain = mills;
            long endTime = System.currentTimeMillis()+mills;
            while (initValue){
                if (hasRemain<=0)
                    throw new TimeOutException("Time out");
                blockThreadCollection.add(Thread.currentThread());
                hasRemain = endTime-System.currentTimeMillis();
            }
            this.initValue = true;
            currenThread = Thread.currentThread();
        }
 
 
    }
 
    @Override
    public synchronized void unlock() {
        if (currenThread==Thread.currentThread()){
            this.initValue = false; //表明鎖已經釋放
            Optional.of(Thread.currentThread().getName()+ " release the lock monitor").ifPresent(System.out::println);
            this.notifyAll();
        }
    }
 
    @Override
    public Collection<Thread> getBlockedThread() {
        return Collections.unmodifiableCollection(blockThreadCollection);
    }
 
    @Override
    public int getBlockSize() {
        return blockThreadCollection.size();
    }
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public class BlockTest {
    public static void main(String[] args) throws InterruptedException {
    final BooleanLock booleanLock = new BooleanLock();
    // 使用Stream流的方式創建四個線程
        Stream.of("T1","T2","T3","T4").forEach(name->{
            new Thread(()->{
                try {
                    booleanLock.lock(10);
                    Optional.of(Thread.currentThread().getName()+" have the lock Monitor").ifPresent(System.out::println);
                    work();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                } catch (Lock.TimeOutException e) {
                    Optional.of(Thread.currentThread().getName()+" time out").ifPresent(System.out::println);
                } finally {
                    booleanLock.unlock();
                }
            },name).start();
        });
    }
 
    //如果是需要一直等待就調用 lock(),如果是超時要退出來就調用超時lock(long millo)
    private static void work() throws InterruptedException{
        Optional.of(Thread.currentThread().getName()+" is       working.....'").ifPresent(System.out::println);
        Thread.sleep(40_000);
    }
}

運行:

T1 have the lock Monitor
T1 is working.....
T2 time out
T4 time out
T3 time out

2.按順序加鎖

>按照順序加鎖是一種有效防止死鎖的機制,但是這種方式,你需要先知道所有可能用到鎖的位置,并對這些鎖安排一個順序

3.死鎖檢測

 >死鎖檢測是一個更好的死鎖預防機制,主要用于超時鎖和按順序加鎖不可用的場景每當一個線程獲得了鎖,會在線程和鎖相關的數據結構中(map、graph 等等)將其記下。除此之外,每當有線程請求鎖,也需要記錄在這個數據結構中。當一個線程請求鎖失敗時,這個線程可以遍歷鎖的關系圖看看是否有死鎖發生。

如果檢測出死鎖,有兩種處理手段:

  • 釋放所有鎖,回退,并且等待一段隨機的時間后重試。這個和簡單的加鎖超時類似,不一樣的是只有死鎖已經發生了才回退,而不會是因為加鎖的請求超時了。雖然有回退和等待,但是如果有大量的線程競爭同一批鎖,它們還是會重復地死鎖,原因同超時類似,不能從根本上減輕競爭.
  • 一個更好的方案是給這些線程設置優先級,讓一個(或幾個)線程回退,剩下的線程就像沒發生死鎖一樣繼續保持著它們需要的鎖。如果賦予這些線程的優先級是固定不變的,同一批線程總是會擁有更高的優先級。為避免這個問題,可以在死鎖發生的時候設置隨機的優先級。

活鎖(Livelock)

什么是活鎖

Java并發編程加鎖導致的活躍性問題詳解方案

死鎖是一直死等,活鎖他不死等,它會一直執行,但是線程就是不能繼續,因為它不斷重試相同的操作。換句話說,就是信息處理線程并沒有發生阻塞,但是永遠都不會前進了,當他們為了彼此間的響應而相互禮讓,使得沒有一個線程能夠繼續前進,那么就發生了活鎖

避免活鎖

? 解決“活鎖”的方案很簡單,謙讓時,嘗試等待一個隨機的時間就可以了。由于等待的時間是隨機的,所以同時相撞后再次相撞的概率就很低了。“等待一個隨機時間”的方案雖然很簡單,卻非常有效,Raft 這樣知名的分布式一致性算法中也用到了它。

饑餓

什么是饑餓

高優先級線程吞噬所有的低優先級線程的 CPU 時間。線程被永久堵塞在一個等待進入同步塊的狀態,因為其他線程總是能在它之前持續地對該同步塊進行訪問。線程在等待一個本身(在其上調用 wait())也處于永久等待完成的對象,因為其他線程總是被持續地獲得喚醒。

Java并發編程加鎖導致的活躍性問題詳解方案

饑餓問題最經典的例子就是哲學家問題。如圖所示:有五個哲學家用餐,每個人要活得兩把叉子才可以就餐。當 2、4 就餐時,1、3、5 永遠無法就餐,只能看著盤中的美食饑餓的等待著。

解決饑餓

Java 不可能實現 100% 的公平性,我們依然可以通過同步結構在線程間實現公平性的提高。

有三種方案:

保證資源充足公平地分配資源避免持有鎖的線程長時間執行

這三個方案中,方案一和方案三的適用場景比較有限,因為很多場景下,資源的稀缺性是沒辦法解決的,持有鎖的線程執行的時間也很難縮短。倒是方案二的適用場景相對來說更多一些。
那如何公平地分配資源呢?在并發編程里,主要是使用公平鎖。所謂公平鎖,是一種先來后到的方案,線程的等待是有順序的,排在等待隊列前面的線程會優先獲得資源。

性能問題

? 并發執行一定比串行執行快嗎?線程越多執行越快嗎?

? 答案是:并發不一定比串行快。因為有創建線程和線程上下文切換的開銷。

上下文切換

什么是上下文切換?

? 當 CPU 從執行一個線程切換到執行另一個線程時,CPU 需要保存當前線程的本地數據,程序指針等狀態,并加載下一個要執行的線程的本地數據,程序指針等。這個開關被稱為“上下文切換”。

減少上下文切換的方法

無鎖并發編程 - 多線程競爭鎖時,會引起上下文切換,所以多線程處理數據時,可以用一些辦法來避免使用鎖,如將數據的 ID 按照 Hash 算法取模分段,不同的線程處理不同段的數據。CAS 算法 - Java 的 Atomic 包使用 CAS 算法來更新數據,而不需要加鎖。使用最少線程 - 避免創建不需要的線程,比如任務很少,但是創建了很多線程來處理,這樣會造成大量線程都處于等待狀態。使用協程 - 在單線程里實現多任務的調度,并在單線程里維持多個任務間的切換。

資源限制

什么是資源限制

? 資源限制是指在進行并發編程時,程序的執行速度受限于計算機硬件資源或軟件資源。

資源限制引發的問題

? 在并發編程中,將代碼執行速度加快的原則是將代碼中串行執行的部分變成并發執行,但是如果將某段串行的代碼并發執行,因為受限于資源,仍然在串行執行,這時候程序不僅不會加快執行,反而會更慢,因為增加了上下文切換和資源調度的時間。

如何解決資源限制的問題

? 在資源限制情況下進行并發編程,根據不同的資源限制調整程序的并發度。

對于硬件資源限制,可以考慮使用集群并行執行程序。對于軟件資源限制,可以考慮使用資源池將資源復用。

到此這篇關于Java并發編程加鎖導致的活躍性問題詳解方案的文章就介紹到這了,更多相關Java 并發編程加鎖內容請搜索服務器之家以前的文章或繼續瀏覽下面的相關文章希望大家以后多多支持服務器之家!

原文鏈接:https://blog.csdn.net/weixin_60707895/article/details/121014522

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 成人小视频免费在线观看 | 久久久久久久黄色片 | 国产成人在线免费看 | 欧美一级高潮片免费的 | 精选久久 | 国产一级毛片网站 | 懂色粉嫩av久婷啪 | 欧洲黄视频 | 在线观看中文字幕av | 欧美精品久久久久久久久老牛影院 | 中文字幕 亚洲一区 | 亚洲精品免费播放 | 毛片午夜 | 亚洲国产精品高潮呻吟久久 | 久久国产精品久久精品国产演员表 | 综合国产在线 | 国产91亚洲精品一区二区三区 | 2021年无线乱码播放高清完整 | 思思久而久而蕉人 | 国产午夜精品一区二区三区嫩草 | 免费福利在线视频 | 91福利社在线 | 一级在线观看视频 | 最新av在线免费观看 | 视频一区二区视频 | 久久影院午夜 | 国产精品久久久久久久久久 | 中文字幕欧美亚洲 | 欧美亚洲国产一区 | 久久久成人精品视频 | 俄罗斯16一20sex牲色另类 | 国产成人77亚洲精品www | 久久国产精品一区 | 91在线视频福利 | 五月天堂婷婷 | 日韩美香港a一级毛片免费 欧美一级淫片007 | 欧美一级aa免费毛片 | 水多视频在线观看 | 国内精品伊人久久久久网站 | 欧美特黄aaa | 久久视频精品 |