java 共享鎖 獨占鎖_java中的公平鎖、非公平鎖、可重入鎖、遞歸鎖、自旋鎖、獨占鎖和共享鎖...

一、公平鎖與非公平鎖

1.1 概述

公平鎖:是指多個線程按照申請鎖的順序來獲取鎖。

非公平鎖:是指在多線程獲取鎖的順序并不是按照申請鎖的順序,有可能后申請的線程比先申請的線程優先獲取到鎖,在高并發的情況下,有可能造成優先級反轉或者饑餓現象。饑餓現象就是低優先級的線程可能一直拿不到鎖,而一直處于等待狀態。

1.2 區別

公平鎖:Threads acquire a fair lock in the order in which they requested it.

公平鎖,就是很公平,在并發環境中,每個線程在獲取鎖時會先查看此鎖維護的等待隊列,如果為空,或者當前線程是等待隊列的第一個,就占有鎖,否則就會加入到等待隊列中,以后會按照 FIFO 的規則從隊列中取到自己。

非公平鎖:a nonfair lock permits barging: threads requesting a lock can jump ahead of the queue of waiting threads if the lock

happens to be available when it is requested.

非公平鎖比較粗魯,上來就直接嘗試占有鎖,如果嘗試失敗,就再采用類似公平鎖那種方式。而且,非公平鎖比公平鎖的吞吐量大。

1.3 Java 中的一些公平鎖和非公平鎖

1. java 中的 ReentrantLock,默認是非公平鎖,當參數 fair 為 true 時,就是公平鎖。

1 /**

2 * Creates an instance of {@code ReentrantLock}.

3 * This is equivalent to using {@code ReentrantLock(false)}.

4 */

5 public ReentrantLock() {

6 sync = new NonfairSync();

7 }

8

9 /**

10 * Creates an instance of {@code ReentrantLock} with the

11 * given fairness policy.

12 *

13 * @param fair {@code true} if this lock should use a fair ordering policy

14 */

15 public ReentrantLock(boolean fair) {

16 sync = fair ? new FairSync() : new NonfairSync();

17 }

2. synchronized 也是一種非公平鎖。

二、可重入鎖與不可重入鎖

2.1 概述

可重入鎖(也叫做遞歸鎖):

指的是同一線程外層函數獲得鎖之后,內層遞歸函數仍然能獲取該鎖的代碼,在同一個線程在外層方法獲取鎖的時候,在進入內層方法會自動獲取鎖,也就是說,線程可以進入任何一個它已經擁有的鎖所同步著的代碼塊。可重入鎖最大的作用就是避免死鎖。

不可重入鎖,即若當前線程執行某個方法已經獲取了該鎖,那么在方法中嘗試再次獲取鎖時,就會獲取不到被阻塞。

2.2 java 中的可重入鎖

2.2.1 synchronized 鎖

1 class Phone {

2 public synchronized void sendSMS() {

3 System.out.println(Thread.currentThread().getName() + "send SMS...");

4 sendEmail();

5 }

6

7 public synchronized void sendEmail() {

8 System.out.println(Thread.currentThread().getName() + "send email...");

9 }

10 }

11

12 public class ReentrantLockDemo {

13

14 public static void main(String[] args) {

15 Phone phone = new Phone();

16

17 new Thread(() -> {

18 phone.sendSMS();

19 }, "Thread1").start();

20

21 new Thread(() -> {

22 phone.sendSMS();

23 }, "Thread2").start();

24 }

25 }a11cbc5ee8b5bec94d9e00181b1e649e.png

2.2.2 ReentrantLock

1 class Phone implements Runnable {

2 Lock lock = new ReentrantLock();

3

4 @Override

5 public void run() {

6 get();

7 }

8

9 public void get() {

10 lock.lock();

11 try {

12 System.out.println(Thread.currentThread().getName() + "get method...");

13 set();

14 } finally {

15 lock.unlock();

16 }

17 }

18

19 public void set() {

20 lock.lock();

21 try {

22 System.out.println(Thread.currentThread().getName() + "set method...");

23 } finally {

24 lock.unlock();

25 }

26 }

27 }

28

29 public class ReentrantLockDemo {

30

31 public static void main(String[] args) {

32 Phone phone = new Phone();

33

34 Thread thread3 = new Thread(phone, "Thread3");

35 Thread thread4 = new Thread(phone, "Thread4");

36 thread3.start();

37 thread4.start();

38 }

39 }

f45d4b2a9ffab84e0862b0913720d8af.png

2.3 面試題

使用 ReentrantLock 時,如果加入兩層鎖呢,程序是直接報編譯錯誤,還是正常運行,正常運行的話,能得到預期的結果嗎?

1 class Phone implements Runnable {

2

3 // ...

4

5 public void get() {

6 lock.lock();

7 lock.lock();

8 try {

9 System.out.println(Thread.currentThread().getName() + "get method...");

10 set();

11 } finally {

12 lock.unlock();

13 lock.unlock();

14 }

15 }

16

17 // ...

18 }

6f4623ba654079ec76d8701c733df09d.png

當缺少 unlock() 時(也就是,lock 和 unlock不是一一對應,lock 比 unlock 多 ),程序不會報編譯錯誤,但得不到預期的結果,從下面可以看出,程序一直處于運行的狀態:

ad347407026e32edb821ea23f6418157.png

當缺少 lock() 時(也就是,unlock 比 lock 多 ),此時,程序也不會報編譯錯誤,控制臺也輸出了結果,但是拋出了 IllegalMonitorStateException 異常。

bdeb585dfaad65b79b5a863bff64d574.png

三、自旋鎖

3.1 概述

自旋鎖是指嘗試獲取鎖的線程不會立即阻塞,而是采用循環的方式去嘗試獲取鎖,這樣的好處是減少線程上下文切換的消耗,缺點是循環會消耗CPU。

3.2 java 中的自旋鎖

1 // Unsafe.java

2 public final int getAndAddInt(Object var1, long var2, int var4) {

3 int var5;

4 do {

5 var5 = this.getIntVolatile(var1, var2);

6 } while(!this.compareAndSwapInt(var1, var2, var5, var5 + var4));

7

8 return var5;

9 }

3.3 手寫一個自旋鎖

1 public class SpinLockDemo {

2

3 AtomicReference atomicReference = new AtomicReference<>();

4

5 public void myLock() {

6 Thread thread = Thread.currentThread();

7 System.out.println(thread.getName() + "come in...");

8 while (!atomicReference.compareAndSet(null, thread)) {

9

10 }

11 }

12

13 public void myUnLock() {

14 Thread thread = Thread.currentThread();

15 atomicReference.compareAndSet(thread, null);

16 System.out.println(thread.getName() + "come out...");

17 }

18

19 public static void main(String[] args) {

20

21 SpinLockDemo spinLockDemo = new SpinLockDemo();

22

23 new Thread(() -> {

24 spinLockDemo.myLock();

25 try {

26 TimeUnit.SECONDS.sleep(5);

27 } catch (InterruptedException e) {

28 e.printStackTrace();

29 }

30 spinLockDemo.myUnLock();

31 }, "Thread1").start();

32

33 try {

34 TimeUnit.SECONDS.sleep(1);

35 } catch (InterruptedException e) {

36 e.printStackTrace();

37 }

38

39 new Thread(() -> {

40 spinLockDemo.myLock();

41 try {

42 TimeUnit.SECONDS.sleep(1);

43 } catch (InterruptedException e) {

44 e.printStackTrace();

45 }

46 spinLockDemo.myUnLock();

47 }, "Thread2").start();

48 }

49 }

四、寫鎖(獨占鎖)、讀鎖(共享鎖)和互斥鎖

4.1 概述

獨占鎖:指該鎖一次只能被一個線程所持有。對 ReentrantLock 和 Synchronized 而言都是獨占鎖。

共享鎖:指該鎖可被多個線程所持有。

對 ReentrantReadWriteLock 其讀鎖是共享鎖,其寫鎖是獨占鎖。

讀鎖的共享鎖可保證并發讀是非常高效的,讀寫,寫讀,寫寫的過程是互斥的。

4.2 示例(模擬緩存)

4.2.1 加鎖前:

數據寫入的時候,被打斷:

1 class MyCache {

2

3 private volatile Map map = new HashMap<>();

4

5 public void put(String key, Object value) {

6 System.out.println(Thread.currentThread().getName() + "正在寫入:" + key);

7 try {

8 TimeUnit.MILLISECONDS.sleep(300);

9 } catch (InterruptedException e) {

10 e.printStackTrace();

11 }

12 map.put(key, value);

13 System.out.println(Thread.currentThread().getName() + "寫入完成");

14 }

15

16 public void get(String key) {

17 System.out.println(Thread.currentThread().getName() + "正在讀取");

18 try {

19 TimeUnit.MILLISECONDS.sleep(300);

20 } catch (InterruptedException e) {

21 e.printStackTrace();

22 }

23 Object result = map.get(key);

24 System.out.println(Thread.currentThread().getName() + "讀取完成:" + result);

25 }

26 }

27

28 public class ReadWriteLockDemo {

29

30 public static void main(String[] args) {

31 MyCache myCache = new MyCache();

32

33 for (int i = 1; i <= 5; i++) {

34 final int temp = i;

35 new Thread(() -> {

36 myCache.put(temp + "", temp + "");

37 }, String.valueOf(i)).start();

38 }

39

40 for (int i = 1; i <= 5; i++) {

41 final int temp = i;

42 new Thread(() -> {

43 myCache.get(temp + "");

44 }, String.valueOf(i)).start();

45 }

46 }

47 }6b2b1949ecd727a8625d658a3db5638d.png

4.2.2 加鎖后:

寫入時正常,不會中斷;讀取時,可以共享鎖。

1 class MyCache {

2

3 private volatile Map map = new HashMap<>();

4 private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();

5

6 public void put(String key, Object value) {

7 rwLock.writeLock().lock();

8 try {

9 System.out.println(Thread.currentThread().getName() + "正在寫入:" + key);

10 try {

11 TimeUnit.MILLISECONDS.sleep(300);

12 } catch (InterruptedException e) {

13 e.printStackTrace();

14 }

15 map.put(key, value);

16 System.out.println(Thread.currentThread().getName() + "寫入完成");

17 } catch (Exception e) {

18 e.printStackTrace();

19 } finally {

20 rwLock.writeLock().unlock();

21 }

22 }

23

24 public void get(String key) {

25 rwLock.readLock().lock();

26 try {

27 System.out.println(Thread.currentThread().getName() + "正在讀取");

28 try {

29 TimeUnit.MILLISECONDS.sleep(300);

30 } catch (InterruptedException e) {

31 e.printStackTrace();

32 }

33 Object result = map.get(key);

34 System.out.println(Thread.currentThread().getName() + "讀取完成:" + result);

35 } catch (Exception e) {

36 e.printStackTrace();

37 } finally {

38 rwLock.readLock().unlock();

39 }

40 }

41 }7b71a2780d6fee824ee9df8cfdbd515a.png

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/540006.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/540006.shtml
英文地址,請注明出處:http://en.pswp.cn/news/540006.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

GoogleNet網絡分析與demo實例

參考自 up主的b站鏈接&#xff1a;霹靂吧啦Wz的個人空間-霹靂吧啦Wz個人主頁-嗶哩嗶哩視頻這位大佬的博客 Fun_機器學習,pytorch圖像分類,工具箱-CSDN博客 1. GoogLeNet網絡詳解 GoogLeNet在2014年由Google團隊提出&#xff08;與VGG網絡同年&#xff0c;注意GoogLeNet中的L大…

解決win10安卓虛擬機每十幾分鐘藍屏重啟問題

2012年第一次接觸android&#xff0c;它的虛擬機是很慢的&#xff0c;如今Intel HAXM 技術為 Android 模擬器加速&#xff0c; 使模擬器運行度媲美真機&#xff0c; 徹底解決模擬器運行慢的問題。問題也是由它而來&#xff0c;因為驅動和系統不兼容造成的。 CPU必須I3及I3以上才…

pg_resetxlog清理的pg_xlog下的WAL日志

PostgreSQL的pg_xlog下有大量日志&#xff0c;空間不足&#xff0c;如何刪除&#xff1f; Darren1:postgres:/usr/local/pgsql/data/pg_xlog:>ls 000000010000000000000008.00000028.backup 00000001000000000000009D 0000000100000000000000C9 0000000100000000000000F5…

mysql備份:一,Xtrabackup

資料來自于馬哥 注明&#xff1a;此工具不能備份出sql語句。另外只能適用innodb存儲引擎。 一、安裝 1、簡介 Xtrabackup是由percona提供的mysql數據庫備份工具&#xff0c;據官方介紹&#xff0c;這也是世界上惟一一款開源的能夠對innodb和xtradb數據庫進行熱備的工具。特點&…

51服務的開啟方式

服務開啟方式的知識點見博文&#xff1a;http://blog.csdn.net/zengmingen/article/details/49425161步驟&#xff1a; 1、新建Android項目名“51服務的開啟方式” 2、新建一個類 MyService&#xff0c;繼承 Service 3、在清單文件里配置第二步建的service 4、在Myservice類中覆…

java mysql 存儲圖片_Java存儲圖片到Mysql

該樓層疑似違規已被系統折疊 隱藏此樓查看此樓【1】視圖層action"${ctx}/web/UserInforServlet?methoduserInforServlet" >更換頭像立即提交重置var layer,upload,form;//1-頁面數據加載$(function () {//【1】加載&初始化layui模塊-彈出層與table數據表格la…

JavaWeb應用配置文件安全解決方案

這里主要說說JavaWeb應用的配置文件安全&#xff0c;通常JavaWeb應用多多少少會有一些配置文件&#xff0c;其中數據源的配置則是關系到數據庫的安全&#xff0c;另外還有一些基于文件的權限配置&#xff0c;應用程序的一些系統參數。鑒于這樣的情況&#xff0c;如果配置文件被…

java 免費cms_開源 免費 java CMS

Bug修復:1.菜單管理&#xff1a;刪除操作按鈕后不能直接進行刪除菜單操作。2.刪除單位時操作記錄不顯示單位名稱問題。3.站點管理&#xff1a;改變所屬站點增加改變為一級站點功能&#xff0c;上傳非圖片logo時雖然提示但仍上傳成功問題。4.模板文件管理&#xff1a;點擊查看/下…

Android加載大圖片不OutOfMemoryError

Android加載圖片時&#xff0c;對于分辨率小&#xff0c;配置低的機子&#xff0c;很容易發生OutOfMemoryError。手機的內存比圖片的大很多&#xff0c;怎么會這樣&#xff1f; 在設置Android虛擬機的內存時&#xff1a; RAM&#xff1a;模擬器的內存空間 VM Heap&#xff1a;…

任務計劃、chkconfig工具、systemd管理服務、unit、target

比如備份數據或者重啟服務。 crontab -u、-e、-l、-r&#xff08;刪除&#xff09; 格式&#xff1a;分 時 日 月 周 user command 文件/var/spool/cron/username 分范圍0-59&#xff0c;時范圍0-23&#xff0c;日范圍1-31&#xff0c;月范圍1-12&#xff0c;周1-7 可用格式1-5…

vue打卡日歷_Vue日歷

new Vue({el: ‘#calendar‘,data: {currentDay: 1,currentMonth: 1,currentYear: 1970,currentWeek: 1,days: [],addDay: [],},created: function() {this.initData(null);var $this this;//請求數據$.ajax({url: "這里填接口名稱",type: "POST",data: {…

android Intent機制詳解

原文出處&#xff1a;http://blog.csdn.net/t12x3456/article/details/7688154 什么是Intent Intent是一種運行時綁定&#xff08;run-time binding&#xff09;機制&#xff0c;它能在程序運行過程中連接兩個不同的組件。通過Intent&#xff0c;你的程序可以向Android表達某種…

python基本數據類型(四)-集合與運算符-python3筆記

1.集合 2.字典 3.運算符優先級 1.集合 創建&#xff1a;() set() 注意&#xff1a;創建空的集合要用set() 特點&#xff1a;元素唯一&#xff0c;無序 運算&#xff1a; &&#xff08;交集&#xff09; |&#xff08;并集&#xff09; -&#xff08;差集&#xff0…

Android的權限

Android有四種權限&#xff1a; 1、Permission 權限 2、Root權限 3、Bootloader的解鎖 4、Radio(基帶)解鎖 ------------------------------------ 1、Permission 我們在開發中經常使用到 Permission 權限&#xff0c;即一系列"Android.Permission.*"對象。…

hive2 java連接_用Java代碼通過JDBC連接Hiveserver2

1.在終端啟動hiveserver2#hiveserver22.使用beeline連接hive另外打開一個終端&#xff0c;輸入如下命令(xavierdb必須是已經存在的數據庫)#beeline -u jdbc:hive2://localhost:10000/xavierdb -n hive -p hive3.添加maven依賴org.apache.hivehive-jdbc1.1.0junitjunit4.9org.ap…

java 向上拋異常_Java 異常的處理方式throws

在昨天的文章《Java 異常的分類與處理》中我們簡單地了解了一下在方法聲明的位置上使用throws關鍵字向上拋出異常&#xff0c;下面深入講解異常的第一種處理方式throws。下面深入講解異常的第一種處理方式throws。看以下例子&#xff1a;import java.io.*;public class Excepti…

Jquery mobile 解決IOS9selectli閃退問題

升級IOS9后&#xff0c;JQuery mobile 出現了個bug問題。<select>&#xff0c;<ul><li></li></ul> 出現閃退。 解決方法&#xff1a; 必須加在 jquery.js 和 jquerymobile.js 中間 <script src"......../...../jquery-2.0.0.min.js&qu…

JAVA通過SSL證書創建MS AD賬戶及設置密碼

近期由于工作需要整理一下自動化的東西&#xff0c;因為公司去年上線了OA&#xff0c;所以公司的入職系統會提交用戶的信息到IT部門&#xff0c;最早的做法是入職到了&#xff0c;IT部門收集用戶信息在AD中創建對應的用戶信息&#xff0c;所以為了提高管理員的工作效率&#xf…

java 實體類規范_實體類的規范

1.Boolean類型1.1.使用Boolean類型,而不是Byte類型1.2.數據庫字段名使用is_開頭1.3.實體類字段名不使用is開頭例子/*** 是否為新消息*/Column(name "is_new_message", nullable false)private Boolean newMessage;2.Enum類型1.使用Convert注解, 并指定coverter類例…

01電話撥號器

實例非常簡單&#xff0c;意在體驗Android的Intent&#xff0c;用戶權限。 Intent 見 http://blog.csdn.net/zengmingen/article/details/49586045 用戶權限 見 http://blog.csdn.net/zengmingen/article/details/49586569 --------------------------------------------------…