日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

java 共享锁 独占锁_java中的公平锁、非公平锁、可重入锁、递归锁、自旋锁、独占锁和共享锁...

發(fā)布時(shí)間:2025/3/11 编程问答 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 共享锁 独占锁_java中的公平锁、非公平锁、可重入锁、递归锁、自旋锁、独占锁和共享锁... 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一、公平鎖與非公平鎖

1.1 概述

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

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

1.2 區(qū)別

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

公平鎖,就是很公平,在并發(fā)環(huán)境中,每個(gè)線程在獲取鎖時(shí)會(huì)先查看此鎖維護(hù)的等待隊(duì)列,如果為空,或者當(dāng)前線程是等待隊(duì)列的第一個(gè),就占有鎖,否則就會(huì)加入到等待隊(duì)列中,以后會(huì)按照 FIFO 的規(guī)則從隊(duì)列中取到自己。

非公平鎖: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,默認(rèn)是非公平鎖,當(dāng)參數(shù) fair 為 true 時(shí),就是公平鎖。

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 概述

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

指的是同一線程外層函數(shù)獲得鎖之后,內(nèi)層遞歸函數(shù)仍然能獲取該鎖的代碼,在同一個(gè)線程在外層方法獲取鎖的時(shí)候,在進(jìn)入內(nèi)層方法會(huì)自動(dòng)獲取鎖,也就是說,線程可以進(jìn)入任何一個(gè)它已經(jīng)擁有的鎖所同步著的代碼塊。可重入鎖最大的作用就是避免死鎖。

不可重入鎖,即若當(dāng)前線程執(zhí)行某個(gè)方法已經(jīng)獲取了該鎖,那么在方法中嘗試再次獲取鎖時(shí),就會(huì)獲取不到被阻塞。

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 }

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 }

2.3 面試題

使用 ReentrantLock 時(shí),如果加入兩層鎖呢,程序是直接報(bào)編譯錯(cuò)誤,還是正常運(yùn)行,正常運(yùn)行的話,能得到預(yù)期的結(jié)果嗎?

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 }

當(dāng)缺少 unlock() 時(shí)(也就是,lock 和 unlock不是一一對應(yīng),lock 比 unlock 多 ),程序不會(huì)報(bào)編譯錯(cuò)誤,但得不到預(yù)期的結(jié)果,從下面可以看出,程序一直處于運(yùn)行的狀態(tài):

當(dāng)缺少 lock() 時(shí)(也就是,unlock 比 lock 多 ),此時(shí),程序也不會(huì)報(bào)編譯錯(cuò)誤,控制臺(tái)也輸出了結(jié)果,但是拋出了 IllegalMonitorStateException 異常。

三、自旋鎖

3.1 概述

自旋鎖是指嘗試獲取鎖的線程不會(huì)立即阻塞,而是采用循環(huán)的方式去嘗試獲取鎖,這樣的好處是減少線程上下文切換的消耗,缺點(diǎn)是循環(huán)會(huì)消耗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 手寫一個(gè)自旋鎖

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 }

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

4.1 概述

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

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

對 ReentrantReadWriteLock 其讀鎖是共享鎖,其寫鎖是獨(dú)占鎖。

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

4.2 示例(模擬緩存)

4.2.1 加鎖前:

數(shù)據(jù)寫入的時(shí)候,被打斷:

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 }

4.2.2 加鎖后:

寫入時(shí)正常,不會(huì)中斷;讀取時(shí),可以共享鎖。

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 }

總結(jié)

以上是生活随笔為你收集整理的java 共享锁 独占锁_java中的公平锁、非公平锁、可重入锁、递归锁、自旋锁、独占锁和共享锁...的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。