一、公平锁与非公平锁

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 }

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 时,如果加入两层锁呢,程序是直接报编译错误,还是正常运行,正常运行的话,能得到预期的结果吗?

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 }

当缺少 unlock() 时(也就是,lock 和 unlock不是一一对应,lock 比 unlock 多 ),程序不会报编译错误,但得不到预期的结果,从下面可以看出,程序一直处于运行的状态:

当缺少 lock() 时(也就是,unlock 比 lock 多 ),此时,程序也不会报编译错误,控制台也输出了结果,但是抛出了 IllegalMonitorStateException 异常。

三、自旋锁

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 }

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 }

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

  1. Java锁之公平和非公平锁

    Java锁之公平和非公平锁 目录 公平锁和非公平锁概念 公平锁和非公平锁区别 ReentrantLock和synchronized是公平锁还是非公平锁? 1. 公平锁和非公平锁概念 公平锁:是指多个线 ...

  2. java并发编程(三十五)——公平与非公平锁实战

    前言 在 java并发编程(十六)--锁的七大分类及特点 一文中我们对锁有各个维度的分类,其中有一个维度是公平/非公平,本文我们来探讨下公平与非公平锁. 公平|非公平 首先,我们来看下什么是公平锁和非 ...

  3. 云阶月地,关锁千重(一.公平和非公平)

    看到文章的标题是不是很诧异,一个搞技术的为什么要搞这么文艺的话题呢?标题说关锁千重,是不是很形象,我们在开发中的锁不也是多种多样么? Lock 既然之前说了锁千重,那锁到底有多少种,他们的分类又是怎么 ...

  4. 公平锁和非公平锁-ReentrantLock是如何实现公平、非公平的

    转载:https://www.jianshu.com/p/5104cd94dbe0 1.什么是公平锁与非公平锁 公平锁:公平锁就是保障了多线程下各线程获取锁的顺序,先到的线程优先获取锁. 非公平锁:非 ...

  5. Java锁的种类以及辨析(四):可重入锁

    Java锁的种类以及辨析(四):可重入锁 本文里面讲的是广义上的可重入锁,而不是单指JAVA下的ReentrantLock. 可重入锁,也叫做递归锁,指的是同一线程 外层函数获得锁之后 ,内层递归函数 ...

  6. java公平索非公平锁_Java 并发编程中使用 ReentrantLock 替代 synchronized

    Java 5 引入的 Concurrent 并发库软件包中,提供了 ReentrantLock 可重入同步锁,用来替代 synchronized 关键字原语,并可提供更好的性能,以及更强大的功能.使用 ...

  7. java公平索非公平锁_java中的非公平锁不怕有的线程一直得不到执行吗

    首先来看公平锁和非公平锁,我们默认使用的锁是非公平锁,只有当我们显示设置为公平锁的情况下,才会使用公平锁,下面我们简单看一下公平锁的源码,如果等待队列中没有节点在等待,则占有锁,如果已经存在等待节点, ...

  8. java B锁_Java中15种锁的介绍

    原标题:Java中15种锁的介绍 在读很多并发文章中,会提及各种各样锁如公平锁,乐观锁等等,这篇文章介绍各种锁的分类.介绍的内容如下: 1.公平锁 / 非公平锁 2.可重入锁 / 不可重入锁 3.独享 ...

  9. java中乐观锁_Java中乐观锁与悲观锁的实现

    锁(locking) 业务逻辑的实现过程中,往往需要保证数据访问的排他性.如在金融系统的日终结算 处理中,我们希望针对某个cut-off时间点的数据进行处理,而不希望在结算进行过程中 (可能是几秒种, ...

最新文章

  1. javabean和EJB的区别
  2. 3位物理学家获基础物理学特别突破奖
  3. PL/SQL developer export/import (转)
  4. LESS-Middleware:Node.js 和 LESS 的完美搭配
  5. 32岁被裁,拿N+1,我高兴地失业了
  6. vista下文件夹拒绝访问的解决办法
  7. PHP中路由和rewrite的使用
  8. 把SWT包装成Plugin需要修改的地方
  9. 计算机课堂热身游戏,电脑课我们常玩的13个小游戏
  10. 6年后再一次Hello World!这本书让你久等了!
  11. Photoshop2023最新版安装教程及下载
  12. 证明调和级数发散的方法
  13. 2023年我终于进阿里了,阿里offer五面经验与总结
  14. js内置对象【学习笔记】
  15. 51单片机之DS18B20温度传感器实验
  16. 电机与matlab突然,同步电机的三相突然短路的MATLAB计算
  17. 职业发展之大数据开发工程师理解
  18. python 断点_断点python_python 断点_python断点定义 - 云+社区 - 腾讯云
  19. 红旗Linux4.1下安装Apahce+Tomcat+PHP+mySQL+vsFTPd实录
  20. WPS表格中使用SQL语句获取动态列

热门文章

  1. n个结点,不同形态的二叉树(数目+生成)
  2. html中css二级联动,html二级联动学习笔记
  3. 编写可靠bash脚本的一些技巧
  4. dlna和miracast可以共存吗_高考化学必备之离子共存问题
  5. php sql取数据生成数组中,php中实现数组生成要执行的sql语句
  6. 房价python爬取_python爬取并解析 重庆2015-2019房价走势
  7. 电脑扫描二维码_线上分享 | 网络工作坊:平板电脑工作术
  8. 关机时无人照管更新正在运行_无法抗拒的未来:无人叉车在内部物流中已成为现实...
  9. python wget安装_Macbook系统环境安装wget的2个方法 - 传统包及Homebrew安装
  10. 电脑打字手指正确姿势_正确的弹琴手型,应该是怎样的?