高併發系列之一:基礎概念

一、思維導圖

在這裏插入圖片描述

二、詳細介紹

1.同步(Synchronous)和異步(Asynchronous)

同步和異步來形容一次方法的調用,同步方法調用一旦開始,要進行下面的操作就必須等待方法的返回;異步方法更像是消息的傳遞,方法調用一旦開始,立馬會返回,調用者無需等待,直接就可以進行後續的操作。
同步執行:
在這裏插入圖片描述
同步執行當調用方法執行完成後並返回結果,才能執行後續代碼。
異步執行:
在這裏插入圖片描述
異步調用的話可用參考ajax,調用方法後不會等到sum方法執行完成,而是直接執行後續代碼。sum方法執行完成後主要通過狀態通知主線程,或者通過回調處理這次異步方法執行的結果

2.臨界區

臨界區用來表示一種公共資源或者共享資源,可以被多個線程使用,但是同一時刻,只能有一個線程擁有他。其他線程想要使用它,就必須等待
比如咱們辦公室只有一臺打印機,小王和小李都想使用打印機,那麼他倆必須排隊。
臨界區是並行程序中需要保護的資源,如果意外出現多個線程同時使用該臨界區資源的情況,很有可能造成程序或者數據錯誤。

3.阻塞和非阻塞

阻塞和非阻塞一般來形容兩個或者多個線程之間相互影響,當一個資源佔用了臨界區資源,那麼其他線程想要使用該臨界區資源時,就必須在臨界區等待,等待會導致線程掛起,這種情況就是阻塞。如果佔着臨界區資源的線程一直不釋放,那麼其他線程就必須阻塞,一致等待下去,直到該資源被釋放。
非阻塞和阻塞正好相反,線程不會因爲其他線程而影響執行

4.死鎖、飢餓鎖、活鎖

這三個都是線程活躍性的問題,當發生該問題時,說明該線程不在活躍,相關線程很難在執行下去了。加鎖是爲了保證線程安全性而做的同步操作,而過度的加鎖可能導致各個線程彼此依賴別的線程已經持有的鎖。就會產生死鎖、飢餓鎖、活鎖的問題。
死鎖:兩個或兩個以上的線程,在執行的過程中,因爭奪資源而產生的一種相互等待的現象,如果沒有外力,那麼他們將一直等待下去,此時稱系統爲死鎖狀態或者說產生了死鎖,相關的線程成爲死鎖線程。
死鎖產生的四個條件

  1. 互斥條件:
    線程對資源的訪問是排他性的,當一個線程佔用該資源時,其他線程想要使用該資源,必須等待,直到資源被釋放。
  2. 請求和保持條件:
    線程T1應該至少保持了一個資源R1的佔用,並且對資源R2請求,而此時,R2正被線程T2佔用中,但自己又對R1資源不釋放。
  3. 不剝奪條件:
    線程已獲得的資源,只有自己執行完成之後釋放,佔有狀態不能被剝奪。
  4. 環路等待條件:
    當線程發生死鎖時,必須有“進程-資源環形鏈”,比如:T1線程等待T2佔有的資源,而T2等待T1佔有的資源。

活鎖:當兩個或者多個線程對同一資源進行佔用時,發現其他線程也想要使用該資源,他就把資源給讓出去,而這些線程都很紳士,發現別人想要佔用該資源,就都會讓出去,這就導致活鎖,誰都讓資源,誰都執行不了資源。
飢餓鎖:當線程T1,T2,T3,等線程都去獲取資源R1,因爲T1的線程的優先級比較低,所以線程一直得不到資源,所以T1有可能永遠等待。
例子git地址

package com.jackking.multithread.lock.lock_demo;


/**
 * @author Created by JackKing on 2020/4/29.
 * 演示死鎖
 */
public class Deadlock {
    public static void main(String[] args) {
        Object obj1 = new Object();
        Object obj2 = new Object();
        Thread t1 = new Thread(new SynAddRunalbe(obj1,obj2,1,2,true));
        t1.setName("thread1");
        t1.start();

        Thread t2 = new Thread(new SynAddRunalbe(obj1,obj2,2,1,false));
        t2.setName("thread2");
        t2.start();
    }
}


class SynAddRunalbe implements Runnable{
    Object obj1;
    Object obj2;
    int a,b;
    boolean flag;

    public SynAddRunalbe(Object obj1, Object obj2, int a, int b, boolean flag) {
        this.obj1 = obj1;
        this.obj2 = obj2;
        this.a = a;
        this.b = b;
        this.flag = flag;
    }

    @Override
    public void run() {
        try {
            if (flag){
                synchronized (obj1){
                    Thread.sleep(100);
                    synchronized (obj2){
                        System.out.print(a+b);
                    }
                }
            }else{
                synchronized (obj2){
                    Thread.sleep(100);
                    synchronized (obj1){
                        System.out.println(a+b);
                    }
                }
            }
        }catch (InterruptedException e){
            System.out.println(e.getMessage());
        }

    }
}

運行方法之後找到自己安裝jdk的bin文件夾裏面,運行命令行窗口,先使用命令:jsp
在這裏插入圖片描述
可以看到,咱們的進程pid爲16292,再執行命令:jstack.exe 16292
在這裏插入圖片描述
可以看到,兩個線程相互等待對方持有的鎖,導致死鎖。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章