【試驗局】ReentrantLock中非公平鎖與公平鎖的性能測試

来源:http://www.cnblogs.com/yulinfeng/archive/2017/05/24/6899316.html
-Advertisement-
Play Games

硬體環境: CPU:AMD Phenom(tm) II X4 955 Processor Memory:8G SSD(128G):/ HDD(1T):/home/ 軟體環境: OS:Ubuntu14.04.3 LTS Java:JDK1.7 關於ReentrantLock中非公平鎖和公平鎖詳細區別以 ...


硬體環境:

  CPU:AMD Phenom(tm) II X4 955 Processor

  Memory:8G

  SSD(128G):/

  HDD(1T):/home/

軟體環境:

  OS:Ubuntu14.04.3 LTS

  Java:JDK1.7

  關於ReentrantLock中非公平鎖和公平鎖詳細區別以及實現方式在這裡不再敘述,有關ReentrantLock的源碼解析參照。

  首先我們用實例驗證,非公平鎖以及公平鎖是否是其介紹的那樣,非公平鎖在獲取鎖的時候會首先進行搶鎖,在獲取鎖失敗後才會將當前線程加入同步隊列隊尾中,而公平鎖則是符合請求的絕對順序,也就是會按照先來後到FIFO。

 1 package com.lock;
 2 
 3 import org.junit.Test;
 4 
 5 import java.util.ArrayList;
 6 import java.util.Collection;
 7 import java.util.Collections;
 8 import java.util.List;
 9 import java.util.concurrent.locks.Lock;
10 import java.util.concurrent.locks.ReentrantLock;
11 
12 /**
13  * Created by yulinfeng on 5/24/17.
14  */
15 public class FairAndUnfairTest {
16     private static Lock fairLock = new ReentrantLockMine(true);
17     private static Lock unfairLock = new ReentrantLockMine(false);
18 
19     @Test
20     public void unfair() throws InterruptedException {
21         testLock("非公平鎖", unfairLock);
22     }
23 
24     @Test
25     public void fair() throws InterruptedException {
26         testLock("公平鎖", fairLock);
27     }
28 
29     private void testLock(String type, Lock lock) throws InterruptedException {
30         System.out.println(type);
31         for (int i = 0; i < 5; i++) {
32             Thread thread = new Thread(new Job(lock)){
33                 public String toString() {
34                     return getName();
35                 }
36             };
37             thread.setName("" + i);
38             thread.start();
39         }
40         Thread.sleep(11000);
41     }
42 
43     private static class Job implements Runnable{
44         private Lock lock;
45         public Job(Lock lock) {
46             this.lock = lock;
47         }
48 
49         public void run() {
50             for (int i = 0; i < 2; i++) {
51                 lock.lock();
52                 try {
53                     Thread.sleep(1000);
54                     System.out.println("獲取鎖的當前線程[" + Thread.currentThread().getName() + "], 同步隊列中的線程" + ((ReentrantLockMine)lock).getQueuedThreads() + "");
55                 } catch (InterruptedException e) {
56                     e.printStackTrace();
57                 } finally {
58                     lock.unlock();
59                 }
60             }
61         }
62     }
63 
64     private static class ReentrantLockMine extends ReentrantLock {  //重新實現ReentrantLock類是為了重寫getQueuedThreads方法,便於我們試驗的觀察
65         public ReentrantLockMine(boolean fair) {
66             super(fair);
67         }
68 
69         @Override
70         protected Collection<Thread> getQueuedThreads() {   //獲取同步隊列中的線程
71             List<Thread> arrayList = new ArrayList<Thread>(super.getQueuedThreads());
72             Collections.reverse(arrayList);
73             return arrayList;
74         }
75     }
76 }

  上面這段代碼:創建5個線程,每個線程中有兩次獲取鎖與釋放鎖的行為。運行代碼觀察結果:

  

  顯然,試驗結果與我們的預期相符。在以非公平鎖的方式獲取鎖,當一個線程在獲取鎖又釋放鎖,但又立即獲取鎖的時候,這個時候這個線程有很大的概率會成功(只是很大概率,試驗結果也有可能不連續兩次獲取鎖)。而公平鎖則不一樣,哪怕是同一個線程連續兩次獲取鎖和釋放鎖,在第一次獲取鎖釋放鎖過後接著準備第二次獲取鎖時,這個時候當前線程會被加入到同步隊列的隊尾。

  那麼有了上面的結果除了說明非公平鎖和公平鎖之間的區別還能說明什麼問題呢?其實,這就是本篇的主題——性能測試。非公平鎖的一個線程連續兩次獲取鎖和釋放鎖的工程中,是沒有做上下文切換的,也就是一共只做了5次上下文切換。而公平鎖實際上做了10次上下文切換。而這個上下文切換的開銷實際是很大的,我們通過測試在10個線程,每個線程獲取100000次鎖的情況下兩者的執行速度,以及使用vmstat命令來統計系統上下文切換的次數(cs欄表示系統每秒切換的上下文次數)。

 1 package com.lock;
 2 
 3 import java.util.ArrayList;
 4 import java.util.Collection;
 5 import java.util.Collections;
 6 import java.util.List;
 7 import java.util.concurrent.BrokenBarrierException;
 8 import java.util.concurrent.CyclicBarrier;
 9 import java.util.concurrent.locks.Lock;
10 import java.util.concurrent.locks.ReentrantLock;
11 
12 /**
13  * 改進後的代碼,利用CyclicBarrier當所有線程執行完畢時,統計執行時間。
14  * Created by yulinfeng on 5/24/17.
15  */
16 public class newFairAndUnfairLockTest {
17     private static Lock lock = new ReentrantLockMine(false);    //非公平鎖
18     //private static Lock lock = new ReentrantLockMine(true);   //公平鎖
19 
20     public static void main(String[] args) throws BrokenBarrierException, InterruptedException {
21         String lockType = "非公平鎖";  //String lockType = "公平鎖"
22         long start = System.currentTimeMillis();
23         CyclicBarrier cyclicBarrier = new CyclicBarrier(10, new Time(lockType, start));     //10個線程執行完畢時,執行Time線程統計執行時間
24 
25         for (int i = 0; i < 10; i++) {
26             Thread thread = new Thread(new Job(lock, cyclicBarrier)){
27                 public String toString() {
28                     return getName();
29                 }
30             };
31             thread.setName("" + i);
32             thread.start();
33         }
34 
35 
36     }
37 
38     private static class Job implements Runnable{
39         private Lock lock;
40         private CyclicBarrier cyclicBarrier;
41         public Job(Lock lock, CyclicBarrier cyclicBarrier) {
42             this.lock = lock;
43             this.cyclicBarrier = cyclicBarrier;
44         }
45 
46         public void run() {
47             for (int i = 0; i < 100000; i++) {
48                 lock.lock();
49                 try {
50                     System.out.println(i+"獲取鎖的當前線程[" + Thread.currentThread().getName() + "], 同步隊列中的線程" + ((ReentrantLockMine)lock).getQueuedThreads() + "");
51                 } finally {
52                     lock.unlock();
53                 }
54             }
55             try {
56                 cyclicBarrier.await();  //計數器+1,直到10個線程都到達
57             } catch (InterruptedException e) {
58                 e.printStackTrace();
59             } catch (BrokenBarrierException e) {
60                 e.printStackTrace();
61             }
62         }
63     }
64 
65     private static class ReentrantLockMine extends ReentrantLock {  //重新實現ReentrantLock類是為了重寫getQueuedThreads方法,便於我們試驗的觀察
66         public ReentrantLockMine(boolean fair) {
67             super(fair);
68         }
69 
70         @Override
71         protected Collection<Thread> getQueuedThreads() {   //獲取同步隊列中的線程
72             List<Thread> arrayList = new ArrayList<Thread>(super.getQueuedThreads());
73             Collections.reverse(arrayList);
74             return arrayList;
75         }
76     }
77 
78 
79     private static class Time implements Runnable {     //用於統計時間
80         private long start ;
81         private String lockType;
82 
83         public Time(String lockType, long start) {
84             this.start = start;
85             this.lockType = lockType;
86         }
87 
88         public void run() {
89             System.out.println(lockType + "耗時:" + String.valueOf(System.currentTimeMillis() - start));
90         }
91     }
92 }

  首先執行非公平鎖,並使用"vmstat 1(每秒實時查看系統資源占用情況)",結果如下:

  

  

  再執行公平鎖,並使用"vmstat 1(每秒實時查看系統資源占用情況)",結果如下:  

   

  

  通過上面的試驗結果可以得出結論,非公平鎖的性能因其系統上下文的切換較少,其性能一般要優於公平鎖。

 

  


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • 一、constant 該函數可以將變數註冊在模塊中,並以服務的形式進行使用。 例如: var app = angular.module("MyModule",[]).constant("pageConfig",{pageSize:10}); 通過以上方式就定義了一個模塊中可用的pageConfig的 ...
  • CentOS上實現一鍵Maven打包並部署到Tomcat的Shell腳本 給這個Shell腳本取個名字,比如叫 deploylab, 將deploylab移到任何已經在系統環境變數的bin目錄下,如: 然後就可以在任意位置直接輸入命令 deploylab 一鍵部署最新代碼到Tomcat了。 ...
  • 在大型項目編碼推進中,涉及到 XML 解析問題時,大多數程式員都不太會選用底層的解析方式直接編碼。 主要存在編碼複雜性、難擴展、難復用....,但如果你是 super 程式員或是一個人的項目,也不妨一試。 Jdom/Dom4j/Xstream... 基於底層解析方式重新組織封裝的開源類庫,簡潔明瞭的 ...
  • 本節探討Java中的類載入機制,利用自定義的ClassLoader實現熱部署 ...
  • Myeclipse2016安裝Aptana 想裝個Aptana,裝了半天,網上說的什麼links方式啊,線上方式啊,都是什麼的浮雲。 所以自己來寫個安裝教程。 一、Aptana簡要介紹 Aptana有JavaScript,JavaScript函數,HTML,CSS語言的Code Assist功能。 ...
  • CNN神經網路架構至少包含一個捲積層 (tf.nn.conv2d)。單層CNN檢測邊緣。圖像識別分類,使用不同層類型支持捲積層,減少過擬合,加速訓練過程,降低記憶體占用率。 TensorFlow加速所有不同類弄捲積層捲積運算。tf.nn.depthwise_conv2d,一個捲積層輸出邊接到另一個捲積 ...
  • 1 導入jar包 1.1 導入Spring的開發包 1.2 導入mybatis的jar包 1.3 導入MySQL的驅動 1.4 導入mybatis與Spring的整合包 1.5 導入junit4.jar包 1.6 導入log4j.jar 1.5 導入c3p0.jar 1.6 導入spring-tes ...
  • 使用CI框架開發了一段時間,發現它容易上手,使用起來也方便,最重要是很輕便,這引起我的興趣去分析該框架的設計。這是國外開源的項目,有一段時間特別火,下麵讓我們來看看唄。 ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...