1. 程式人生 > >鎖和多執行緒:鎖的5種分類(三)

鎖和多執行緒:鎖的5種分類(三)

重入鎖  中斷鎖  公平鎖  讀寫鎖  自旋鎖 

 

 

搞明白 執行緒 多執行緒系列

1.重入鎖

在類中有 synchronized 方法A 和 synchronized 方法B,並在A中呼叫B,就形成了重入鎖.獲得A的物件鎖,可以直接呼叫B,並不需要重新請求鎖許可權.

package thread;

/**
 * @Author lyf
 * @Date 2018/11/18 0018 14:30
 */
public class RepeatLock {
  
  public synchronized void A(){
    System.out.println("進入A...");
    B();
  }
  
  public synchronized void B(){
    System.out.println("進入B...");
  }
  
  public static void main(String[] args)
{ RepeatLock repeatLock = new RepeatLock(); for (int i = 0; i < 5; i++) { new Thread(()->{repeatLock.A();}).start(); } } }

 


 

 

2.中斷鎖

使用synchronized修飾的方法,在阻塞狀態blocked時不能被外部打斷,除非jvm報錯.
使用ReentrantLock中的lockInterruptibly()處於阻塞狀態時, 可以被打斷.

package thread;

import java.util.concurrent.locks.ReentrantLock;

/**
 * @Author lyf
 * @Date 2018/11/18 0018 14:47
 */
public class InterruptLock {

  private ReentrantLock lock = new ReentrantLock();

  public synchronized void A() {
       try {
    System.out.println(Thread.currentThread().getName() + "獲取鎖...");
      while (true) {
        Thread.sleep(1000);
        System.out.println(Thread.currentThread().getName() + "執行...");
      }
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }

  public static void main(String[] args) throws InterruptedException {
    
    InterruptLock lock1 = new InterruptLock();
    Thread t1 = new Thread(()->{lock1.A();});
    t1.start();
    Thread t2 = new Thread(()->{lock1.A();});
    t2.start();
    Thread.sleep(2000);
    System.out.println(t1.getName() + ": "+t1.getState());// RUNNABLE 正在執行
    System.out.println(t2.getName() + ": "+t2.getState());// BLOCKED 阻塞狀態
    Thread.sleep(1000);
    t2.interrupt();// 打斷t2執行緒
    System.out.println(t2.getName() + ": "+t2.getState());// 依然處於BLOCKED 阻塞狀態
  }
}

 


 
執行緒0獲取鎖後, 執行緒1進入阻塞等待狀態.對執行緒1呼叫interrupt()打斷執行緒,發現沒什麼用!執行緒1還是在等待.

 

package thread;

import java.util.concurrent.locks.ReentrantLock;

/**
 * @Author lyf
 * @Date 2018/11/18 0018 14:47
 */
public class InterruptLock {

  private ReentrantLock lock = new ReentrantLock();


  public void B() {
    try {
      lock.lockInterruptibly();
      System.out.println(Thread.currentThread().getName() + "獲取鎖...");
      while (true) {
        Thread.sleep(1000);
        System.out.println(Thread.currentThread().getName() + "執行...");
      }
    } catch (InterruptedException e) {
      System.out.println(Thread.currentThread().getName() + "被打斷...");
    } finally {
      lock.unlock();
    }
  }

  public static void main(String[] args) throws InterruptedException {
    
    InterruptLock lock2 = new InterruptLock();
    Thread t1 = new Thread(() -> { lock2.B(); });
    t1.start();
    Thread t2 = new Thread(() -> { lock2.B(); });
    t2.start();
    Thread.sleep(2000);
    System.out.println(t1.getName() + ": "+t1.getState());// RUNNABLE 正在執行
    System.out.println(t2.getName() + ": "+t2.getState());// WAITING 等待狀態
    Thread.sleep(1000);
    t2.interrupt();// 打斷t2執行緒
    System.out.println(t2.getName() + ": "+t2.getState());// WAITING 狀態(執行緒延時)
  }
}

 


 
很明顯執行緒1被打斷...

 

3.公平鎖

當多個執行緒處於阻塞狀態時,由系統隨機排程其中一個執行緒繼續執行,無法保證公平性.有可能某個執行緒永遠無法執行.ReentrantLock(true)可以建立公平鎖,保證每個阻塞的執行緒都可以被執行到.

首先,來看非公平鎖的情況,使用new ReentrantLock()建立:

package thread;

import java.util.concurrent.locks.ReentrantLock;

/**
 * @Author lyf
 * @Date 2018/11/18 0018 18:46
 */
public class FairLock {

  private ReentrantLock lock = new ReentrantLock();

  public synchronized void A() {
    lock.lock();
    System.out.println(Thread.currentThread().getName() + "獲得鎖...");
    try {
      Thread.sleep(5000);
      System.out.println(Thread.currentThread().getName() + "執行...");
    } catch (InterruptedException e) {
      e.printStackTrace();
    } finally {
      lock.unlock();
    }
  }

  public static void main(String[] args) throws InterruptedException {
    FairLock fairLock = new FairLock();
    new Thread(() -> {
      fairLock.A();
    }).start();// 啟動執行緒獲得鎖

    for (int i = 0; i < 5; i++) {
      new Thread(() -> {
        System.out.println(Thread.currentThread().getName() + "等待獲得鎖...");
        fairLock.A();
      }).start();
    }
  }
}

 


 
執行緒0獲得鎖,執行緒 4 3 5 2 1 依次進入等待狀態,線上程0執行完後,隨機選擇一個執行緒執行.

 

使用new ReentrantLock(true)建立公平鎖

private ReentrantLock lock = new ReentrantLock(true);

 


 
執行緒0獲得鎖, 執行緒 1 2 5 4 3 依次進入等待狀態,線上程0執行完後,按照 順序 3 4 5 2 1 執行.

 

4.讀寫鎖

多個執行緒執行讀操作時,互不影響.但是讀寫互斥,寫寫互斥.

package thread;

import java.util.concurrent.locks.ReentrantReadWriteLock;

/**
 * @Author lyf
 * @Date 2018/11/18 0018 10:30
 */
public class MyReadWriteLock {

  private ReentrantReadWriteLock rwl = new ReentrantReadWriteLock();
  private int num = 0;

  public void readFile() {
    rwl.readLock().lock();
    try {
      System.out.println(Thread.currentThread().getName() + "執行讀操作...");
      Thread.sleep((long) (Math.random() * 1000));
      System.out.println(Thread.currentThread().getName() + "讀操作完成...");
    } catch (InterruptedException e) {
      e.printStackTrace();
    } finally {
      rwl.readLock().unlock();
    }
  }


  public void writeFile() {
    rwl.writeLock().lock();
    System.out.println(Thread.currentThread().getName() + "執行寫操作...");
    try {
      num++;
      Thread.sleep((long) (Math.random() * 1000));
      System.out.println(Thread.currentThread().getName() + "寫操作完成...num: " + num);
    } catch (InterruptedException e) {
      e.printStackTrace();
    } finally {
      rwl.writeLock().unlock();
    }

  }

  public static void main(String[] args) {

    MyReadWriteLock myReadWriteLock = new MyReadWriteLock();
    for (int i = 0; i < 5; i++) {
      new Thread(()->{myReadWriteLock.readFile();}).start();// 讀語句1
      new Thread(()->{myReadWriteLock.readFile();}).start();// 讀語句2
      new Thread(() -> { myReadWriteLock.writeFile(); }).start();// 寫語句
    }
  }
}

 


 

 

  • 執行緒0 1 3讀操作同時開始,與執行緒5寫操作互斥
  • 執行緒5寫操作與執行緒2寫操作互斥

5.自旋鎖

多執行緒下會造成執行緒處於阻塞狀態,不能執行其他操作.自旋鎖是一種非阻塞鎖,允許執行緒等待期間執行其他操作,直到獲得鎖.

package thread;

import java.util.concurrent.atomic.AtomicReference;

/**
 * @Author lyf
 * @Date 2018/11/18 0018 20:23
 */
public class SpinLock {
  // CAS操作
  AtomicReference<Thread> runThread = new AtomicReference<>();

  public void lock() {
    Thread cur = Thread.currentThread();// 獲取當前執行緒
    // 如果需要執行執行緒標誌為null,也就是說現在沒有執行緒在執行,就執行當前執行緒
    // 如果需要執行執行緒標誌不為null,說明現在有執行緒在執行,就自己個兒執行自己的
    while (!runThread.compareAndSet(null, cur)) {
      try {
        Thread.sleep(500);
      } catch (InterruptedException e) {
        e.printStackTrace();
      }
      System.out.println(Thread.currentThread().getName() + "在自旋中...");
    }
    try {
      System.out.println(Thread.currentThread().getName() + "開始執行...");
      Thread.sleep(2000);
      System.out.println(Thread.currentThread().getName() + "執行完畢...");
    } catch (InterruptedException e) {
      e.printStackTrace();
    }
  }

  public void unlock() {
    Thread cur = Thread.currentThread();
    runThread.compareAndSet(cur, null);
  }
  
  public static void main(String[] args) {
      SpinLock spinLock = new SpinLock();
      Thread t1 = new Thread(()->{
        spinLock.lock();
        try {
          Thread.sleep(
            
           

相關推薦

執行:5分類()

重入鎖  中斷鎖  公平鎖  讀寫鎖  自旋鎖    1.重入鎖 2.中斷鎖 3.公平鎖 4.讀寫鎖

執行:執行建立3方式(一)

執行緒  鎖Synchronized  搞明白 執行緒 鎖和多執行緒系列 1.執行緒建立 執行緒建立常見的三種方式: 繼承Thread類 實現Runnable介面

libevent原始碼分析--執行

寫在前面: ​ 這個原始碼是分析libevent-2.0.20-stable, 並非最新版本的libevent,作者並沒有全看原始碼,在這裡會推薦以下參考的一些網站,也歡迎大家在不足的地方提出來進行討論。 鎖 ​ libevent的內部實現不需要多執行緒,

sleep/usleep執行的注意事項

最近在寫一個OJ後臺程式,一個主執行緒隔500毫秒讀取一次資料庫把任務放入佇列中,起了4個執行緒用於處理任務(主要是得到任務,然後去資料庫裡讀提交上來的程式碼). 主執行緒 while(true){ pthrea_lock_mutex(&conn_mutex);//

java執行同步5方法

一、引言前幾天面試,被大師虐殘了,好多基礎知識必須得重新拿起來啊。閒話不多說,進入正題。二、為什麼要執行緒同步因為當我們有多個執行緒要同時訪問一個變數或物件時,如果這些執行緒中既有讀又有寫操作時,就會導致變數值或物件的狀態出現混亂,從而導致程式異常。舉個例子,如果一個銀行賬戶

執行基礎5 Lock

1.同步 * 使用ReentrantLock類的lock()和unlock()方法進行同步 2.通訊 * 使用ReentrantLock類的newCondition()方法可以獲取Condition物件 * 需要等待的時候使用Condition的await()方法, 喚醒的時候用signal()

執行設計模式:第篇 - 生產者-消費者模式讀寫模式

一,生產者-消費者模式         生產者-消費者模式是比較常見的一種模式,當生產者和消費者都只有一個的時候,這種模式也被稱為 Pipe模式,即管道模式。      &nb

java執行5.1 -基礎

什麼是鎖 提到多執行緒,立馬就有人說加鎖,什麼是鎖,為什麼加鎖? 鎖:從字面意義,什麼東西加了鎖,那麼就只有有鑰匙的人才能使用,多執行緒中的鎖,也是這個意思。 為什麼加鎖:當單執行緒的時候,無論訪問什麼資源,都不需要考慮鎖的問題,但是當多個執行緒訪問同一個資源,就會發生很多千奇百怪的

執行,兩實現方式(繼承Thread,實現Runnable介面),設定獲取名字,同步程式碼塊、方法,死

1.多執行緒的引入(瞭解) 1.什麼是執行緒 執行緒是程式執行的一條路徑, 一個程序中可以包含多條執行緒 多執行緒併發執行可以提高程式的效率, 可以同時完成多項工作 2.多執行緒的應用場景 紅蜘蛛同時共享螢幕給多個電腦 迅雷開啟多條執行緒一起下載 Q

【Java執行 優化】狀態切換

引言 在多執行緒併發程式設計中Synchronized一直是元老級角色,很多人都會稱呼它為重量級鎖,但是隨著Java SE1.6對Synchronized進行了各種優化之後,有些情況下它並不那麼重了,本文詳細介紹了Java SE1.6中為了減少獲得鎖和

Java執行執行(九)——死

Java中的死鎖指的就是一種多於兩個執行緒永遠阻塞的特殊狀況。Java中的死鎖狀態至少需要多於兩個執行緒以及資源的時候才會產生。這裡,我寫了一個產生死鎖的程式,並且講下如何分析死鎖。 首先來看一下產生死鎖的程式: package com.sapphire

java中的互斥,訊號量執行等待機制

互斥鎖和訊號量都是作業系統中為併發程式設計設計基本概念,互斥鎖和訊號量的概念上的不同在於,對於同一個資源,互斥鎖只有0和1 的概念,而訊號量不止於此。也就是說,訊號量可以使資源同時被多個執行緒訪問,而互斥鎖同時只能被一個執行緒訪問 互斥鎖在java中的實現就是 Reetr

lock執行

import threadingimport timedef run(n): lock.acquire() global num num +=1 lock.release() time.sleep(1)lock = threading.Lock()num = 0t_objs =

Java執行——概念與優化

為了效能與使用的場景,Java實現鎖的方式有非常多。而關於鎖主要的實現包含synchronized關鍵字、AQS框架下的鎖,其中的實現都離不開以下的策略。 悲觀鎖與樂觀鎖 樂觀鎖。樂觀的想法,認為併發讀多寫少。每次操作的時候都不上鎖,直到更新的時候才通過CAS判斷更新。對於AQS框架下的鎖,初始就是

Python中的執行程式設計,執行安全與(一) 聊聊Python中的GIL 聊聊Python中的GIL python基礎之執行機制 python--threading執行總結 Python3入門之執行threading常用方法

1. 多執行緒程式設計與執行緒安全相關重要概念 在我的上篇博文 聊聊Python中的GIL 中,我們熟悉了幾個特別重要的概念:GIL,執行緒,程序, 執行緒安全,原子操作。 以下是簡單回顧,詳細介紹請直接看聊聊Python中的GIL  GIL:&n

執行的4建立方法對比

Java多執行緒實現方式 Java 多執行緒實現方式主要有四種,繼承Thread,實現Runnable,實現Callable,Future實現返回結果的多執行緒。 1. 繼承Thread類建立 public class MyThread extends Thre

java-雙重檢查為什麼執行不安全

如下程式碼所示: public class doubleCheck{ private static Instance instance; public static Instance getInstance(){ if(instance==null){ //1

建立Java執行的兩方式執行異常

一.使用多執行緒的兩種方法  使用多執行緒的兩種方法有:繼承Thread類和實現runable介面。 二.繼承Thread類 來看一下thread類的原始碼:  class Thread implements Runnable { 首先可以看出thread類也是實現Runable介面的run方法如下:

執行”要點

  一個物件裡面如果有多個synchronized方法,某一個時刻內,只要一個執行緒去呼叫其中的一個synchronized方法了,其它的執行緒都只能等待,換句話說,某一個時刻內,只能有唯一一個執行緒去訪問這些synchronized方法   鎖的是當前物件t

c++ 執行 (互斥)

多執行緒程式,如果涉及到對共享資源的併發讀寫,就會產生資源爭用(Data Race)。解決資源爭用,最直接的想法是引入鎖,對併發讀寫的資料進行保護(更高階的則包括無鎖程式設計—— Lock Free Programming)。但是,鎖又有很多種類,例如:自旋鎖(Spinlock)、互斥鎖(Mutex