91超碰碰碰碰久久久久久综合_超碰av人澡人澡人澡人澡人掠_国产黄大片在线观看画质优化_txt小说免费全本

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

java中各類鎖的機制是什么

發布時間:2022-03-04 10:29:25 來源:億速云 閱讀:250 作者:小新 欄目:開發技術

這篇文章給大家分享的是有關java中各類鎖的機制是什么的內容。小編覺得挺實用的,因此分享給大家做個參考,一起跟隨小編過來看看吧。

前言

總結java常見的鎖

區分各個鎖機制以及如何使用

使用方法鎖名
考察線程是否要鎖住同步資源樂觀鎖和悲觀鎖
鎖住同步資源后,要不要阻塞不阻塞可以使用自旋鎖
一個線程多個流程獲取同一把鎖可重入鎖
多個線程公用一把鎖讀寫鎖(寫的共享鎖)
多個線程競爭要不要排隊公平鎖與非公平鎖

1. 樂觀鎖與悲觀鎖

悲觀鎖:不能同時進行多人,執行的時候先上鎖。傳統的關系型數據庫里邊就用到了很多這種鎖機制,比如行鎖,表鎖等,讀鎖,寫鎖等,都是在做操作之前先上鎖

樂觀鎖:通過版本號一致與否,即給數據加上版本,同步更新數據以及加上版本號。不會上鎖,判斷版本號,可以多人操作,類似生活中的搶票。每次去拿數據的時候都認為別人不會修改,所以不會上鎖,但是在更新的時候會判斷一下在此期間別人有沒有去更新這個數據,可以使用版本號等機制。樂觀鎖適用于多讀的應用類型,這樣可以提高吞吐量。Redis就是利用這種check-and-set機制實現事務的

(樂觀鎖可以使用版本號機制和CAS算法實現)

java中各類鎖的機制是什么

通過具體案例演示悲觀鎖和樂觀鎖

在redis框架中

執行multi之前,執行命令watch

具體格式如下

watch key1 [key2]

具體代碼格式如下

127.0.0.1:6379> flushdb
OK
127.0.0.1:6379> set add 100
OK
127.0.0.1:6379> watch add
OK
127.0.0.1:6379> multi
OK
127.0.0.1:6379(TX)> incrby add 20
QUEUED
127.0.0.1:6379(TX)> exec
1) (integer) 120
127.0.0.1:6379>

flushdb是清空數據庫

java中各類鎖的機制是什么

但如果在另一個服務器上,輸入exec,會顯示出錯

因為用的是樂觀鎖,被修改了之后版本會發生改變

總的來說:

悲觀鎖:單獨每個人完成事情的時候,執行上鎖解鎖。解決并發中的問題,不支持并發操作,只能一個一個操作,效率低

樂觀鎖:每執行一件事情,都會比較數據版本號,誰先提交,誰先提交版本號

2. 公平鎖與非公平鎖

公平鎖:先來先到

非公平鎖:不是按照順序,可插隊

  • 公平鎖:效率相對低

  • 非公平鎖:效率高,但是線程容易餓死

通過這個函數Lock lock = new ReentrantLock(true);。創建一個可重入鎖,true 表示公平鎖,false 表示非公平鎖。默認非公平鎖

通過查看源碼

帶有參數的ReentrantLock(true)為公平鎖

ReentrantLock(false)為非公平鎖

主要是調用NonfairSync()與FairSync()

public ReentrantLock() {
        sync = new NonfairSync();
    }

    /**
     * Creates an instance of {@code ReentrantLock} with the
     * given fairness policy.
     *
     * @param fair {@code true} if this lock should use a fair ordering policy
     */
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

具體其非公平鎖與公平鎖的源碼

查看公平鎖的源碼

static final class FairSync extends Sync {
   private static final long serialVersionUID = -3000897897090466540L;

  /**
  * Acquires only if reentrant or queue is empty.
   */
  final boolean initialTryLock() {
   Thread current = Thread.currentThread();
   int c = getState();
   if (c == 0) {
   if (!hasQueuedThreads() && compareAndSetState(0, 1)) {
     setExclusiveOwnerThread(current);
      return true;
    }
    } else if (getExclusiveOwnerThread() == current) {
      if (++c < 0) // overflow
          throw new Error("Maximum lock count exceeded");
         setState(c);
         return true;
       }
    return false;
}

通過代碼實例具體操作

//第一步  創建資源類,定義屬性和和操作方法
class LTicket {
    //票數量
    private int number = 30;

    //創建可重入鎖
    private final ReentrantLock lock = new ReentrantLock(true);
    //賣票方法
    public void sale() {
        //上鎖
        lock.lock();
        try {
            //判斷是否有票
            if(number > 0) {
                System.out.println(Thread.currentThread().getName()+" :賣出"+(number--)+" 剩余:"+number);
            }
        } finally {
            //解鎖
            lock.unlock();
        }
    }
}

public class LSaleTicket {
    //第二步 創建多個線程,調用資源類的操作方法
    //創建三個線程
    public static void main(String[] args) {

        LTicket ticket = new LTicket();

new Thread(()-> {
    for (int i = 0; i < 40; i++) {
        ticket.sale();
    }
},"AA").start();

        new Thread(()-> {
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        },"BB").start();

        new Thread(()-> {
            for (int i = 0; i < 40; i++) {
                ticket.sale();
            }
        },"CC").start();
    }
}

結果截圖如下

java中各類鎖的機制是什么

都是A線程執行,而BC線程都沒執行到,出現了非公平鎖

具體改變其設置可以通過可重入鎖中的一個有參構造方法

修改代碼為private final ReentrantLock lock = new ReentrantLock(true);

代碼截圖為

java中各類鎖的機制是什么

3. 可重入鎖

可重入鎖也叫遞歸鎖

而且有了可重入鎖之后,破解第一把之后就可以一直進入到內層結構

Object o = new Object();
new Thread(()->{
    synchronized(o) {
        System.out.println(Thread.currentThread().getName()+" 外層");

        synchronized (o) {
            System.out.println(Thread.currentThread().getName()+" 中層");

            synchronized (o) {
                System.out.println(Thread.currentThread().getName()+" 內層");
            }
        }
    }

},"t1").start();

synchronized (o)代表鎖住當前{ }內的代碼塊

以上都是synchronized鎖機制

下面講解lock鎖機制

public class SyncLockDemo {

    public synchronized void add() {
        add();
    }

    public static void main(String[] args) {
        //Lock演示可重入鎖
        Lock lock = new ReentrantLock();
        //創建線程
        new Thread(()->{
            try {
                //上鎖
                lock.lock();
                System.out.println(Thread.currentThread().getName()+" 外層");

                try {
                    //上鎖
                    lock.lock();
                    System.out.println(Thread.currentThread().getName()+" 內層");
                }finally {
                    //釋放鎖
                    lock.unlock();
                }
            }finally {
                //釋放做
                lock.unlock();
            }
        },"t1").start();

        //創建新線程
        new Thread(()->{
            lock.lock();
            System.out.println("aaaa");
            lock.unlock();
        },"aa").start();
        }
 }

在同一把鎖中的嵌套鎖,內部嵌套鎖沒解鎖還是可以輸出,但是如果跳出該線程,執行另外一個線程就會造成死鎖

要把握上鎖與解鎖的概念,都要寫上

java中各類鎖的機制是什么

4. 讀寫鎖(共享鎖與獨占鎖)

讀鎖是共享鎖,寫鎖是獨占鎖

  • 共享鎖的一種具體實現

  • 讀寫鎖管理一組鎖,一個是只讀的鎖,一個是寫鎖。

讀寫鎖:一個資源可以被多個讀線程訪問,也可以被一個寫線程訪問,但不能同時存在讀寫線程,讀寫互斥,讀讀共享(寫鎖獨占,讀鎖共享,寫鎖優先級高于讀鎖)

讀寫鎖ReentrantReadWriteLock

讀鎖為ReentrantReadWriteLock.ReadLock,readLock()方法

寫鎖為ReentrantReadWriteLock.WriteLock,writeLock()方法

創建讀寫鎖對象private ReadWriteLock rwLock = new ReentrantReadWriteLock();

寫鎖 加鎖 rwLock.writeLock().lock();,解鎖為rwLock.writeLock().unlock();

讀鎖 加鎖rwLock.readLock().lock();,解鎖為rwLock.readLock().unlock();

案例分析:

模擬多線程在map中取數據和讀數據

完整代碼如下

//資源類
class MyCache {
    //創建map集合
    private volatile Map<String,Object> map = new HashMap<>();

    //創建讀寫鎖對象
    private ReadWriteLock rwLock = new ReentrantReadWriteLock();

    //放數據
    public void put(String key,Object value) {
        //添加寫鎖
        rwLock.writeLock().lock();

        try {
            System.out.println(Thread.currentThread().getName()+" 正在寫操作"+key);
            //暫停一會
            TimeUnit.MICROSECONDS.sleep(300);
            //放數據
            map.put(key,value);
            System.out.println(Thread.currentThread().getName()+" 寫完了"+key);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            //釋放寫鎖
            rwLock.writeLock().unlock();
        }
    }

    //取數據
    public Object get(String key) {
        //添加讀鎖
        rwLock.readLock().lock();
        Object result = null;
        try {
            System.out.println(Thread.currentThread().getName()+" 正在讀取操作"+key);
            //暫停一會
            TimeUnit.MICROSECONDS.sleep(300);
            result = map.get(key);
            System.out.println(Thread.currentThread().getName()+" 取完了"+key);
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            //釋放讀鎖
            rwLock.readLock().unlock();
        }
        return result;
    }
}

public class ReadWriteLockDemo {
    public static void main(String[] args) throws InterruptedException {
        MyCache myCache = new MyCache();
        //創建線程放數據
        for (int i = 1; i <=5; i++) {
            final int num = i;
            new Thread(()->{
                myCache.put(num+"",num+"");
            },String.valueOf(i)).start();
        }

        TimeUnit.MICROSECONDS.sleep(300);

        //創建線程取數據
        for (int i = 1; i <=5; i++) {
            final int num = i;
            new Thread(()->{
                myCache.get(num+"");
            },String.valueOf(i)).start();
        }
    }
}

5. 互斥鎖

互斥鎖是獨占鎖的一種常規實現,是指某一資源同時只允許一個訪問者對其進行訪問,具有唯一性和排它性

pthread_mutex_t mutex=PTHREAD_MUTEX_INITIALIZER;//創建互斥鎖并初始化

pthread_mutex_lock(&mutex);//對線程上鎖,此時其他線程阻塞等待該線程釋放鎖

//要執行的代碼段

pthread_mutex_unlock(&mutex);//執行完后釋放鎖

6. 自旋鎖

查看百度百科的解釋,具體如下 :

它是為實現保護共享資源而提出一種鎖機制。其實,自旋鎖與互斥鎖比較類似,它們都是為了解決對某項資源的互斥使用。無論是互斥鎖,還是自旋鎖,在任何時刻,最多只能有一個保持者,也就說,在任何時刻最多只能有一個執行單元獲得鎖。但是兩者在調度機制上略有不同。對于互斥鎖,如果資源已經被占用,資源申請者只能進入睡眠狀態。但是自旋鎖不會引起調用者睡眠,如果自旋鎖已經被別的執行單元保持,調用者就一直循環在那里看是否該自旋鎖的保持者已經釋放了鎖,"自旋"一詞就是因此而得名

通俗的來說就是一個線程在獲取鎖的時候,如果鎖已經被其它線程獲取,那么該線程將循環等待,然后不斷的判斷鎖是否能夠被成功獲取,直到獲取到鎖才會退出循環。獲取鎖的線程一直處于活躍狀態,但是并沒有執行任何有效的任務。

其特點:

  1. 持有鎖時間等待過長,消耗CPU

  2. 無法滿足等待時間最長的線程優先獲取鎖。不公平的鎖就會存在“線程饑餓”問題

  3. 自旋鎖不會使線程狀態發生切換,處于用戶態(不會到內核態進行線程的狀態轉換),一直都是活躍,不會使線程進入阻塞狀態,減少了不必要的上下文切換,執行速度快。

其模擬算法如下

do{
	b=1;
	while(b){
		lock(bus);
		b = test_and_set(&lock);
		unlock(bus);
	}
	//臨界區
	//lock = 0;
	//其余部分
}while(1)

7. 無鎖 / 偏向鎖 / 輕量級鎖 / 重量級鎖

  • 無鎖:沒有對資源進行鎖定,所有的線程都能訪問并修改同一個資源,但同時只有一個線程能修改成功

  • 偏向鎖:是指一段同步代碼一直被一個線程所訪問,那么該線程會自動獲取鎖,降低獲取鎖的代價

  • 輕量級鎖:鎖是偏向鎖的時候,被另外的線程所訪問,偏向鎖就會升級為輕量級鎖,其他線程會通過自旋的形式嘗試獲取鎖,不會阻塞,從而提高性能

  • 重量級鎖:線程并發加劇,線程的自旋超過了一定次數,或者一個線程持有鎖,一個線程在自旋,還有線程要訪問

感謝各位的閱讀!關于“java中各類鎖的機制是什么”這篇文章就分享到這里了,希望以上內容可以對大家有一定的幫助,讓大家可以學到更多知識,如果覺得文章不錯,可以把它分享出去讓更多的人看到吧!

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

新余市| 焉耆| 隆安县| 铁岭县| 紫金县| 永泰县| 北安市| 双辽市| 西安市| 罗江县| 海伦市| 孝感市| 浮山县| 湘阴县| 东城区| 淮安市| 和田县| 正镶白旗| 沂源县| 治多县| 饶阳县| 淮阳县| 崇州市| 靖边县| 秦安县| 永仁县| 万源市| 丰顺县| 黎川县| 杭锦旗| 阿瓦提县| 扶风县| 丽水市| 新昌县| 高雄县| 辰溪县| 新巴尔虎右旗| 镇原县| 蓬溪县| 平阳县| 平利县|