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.mzph.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大…

51服务的开启方式

服务开启方式的知识点见博文&#xff1a;http://blog.csdn.net/zengmingen/article/details/49425161步骤&#xff1a; 1、新建Android项目名“51服务的开启方式” 2、新建一个类 MyService&#xff0c;继承 Service 3、在清单文件里配置第二步建的service 4、在Myservice类中覆…

JavaWeb应用配置文件安全解决方案

这里主要说说JavaWeb应用的配置文件安全&#xff0c;通常JavaWeb应用多多少少会有一些配置文件&#xff0c;其中数据源的配置则是关系到数据库的安全&#xff0c;另外还有一些基于文件的权限配置&#xff0c;应用程序的一些系统参数。鉴于这样的情况&#xff0c;如果配置文件被…

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通过SSL证书创建MS AD账户及设置密码

近期由于工作需要整理一下自动化的东西&#xff0c;因为公司去年上线了OA&#xff0c;所以公司的入职系统会提交用户的信息到IT部门&#xff0c;最早的做法是入职到了&#xff0c;IT部门收集用户信息在AD中创建对应的用户信息&#xff0c;所以为了提高管理员的工作效率&#xf…

01电话拨号器

实例非常简单&#xff0c;意在体验Android的Intent&#xff0c;用户权限。 Intent 见 http://blog.csdn.net/zengmingen/article/details/49586045 用户权限 见 http://blog.csdn.net/zengmingen/article/details/49586569 --------------------------------------------------…

02发送短信

使用SmsManager发送短信java.lang.Object ↳android.telephony.SmsManagerManages SMS operations such as sending data, text, and pdu SMS messages. Get this object by calling the static method SmsManager.getDefault().管理短信操作&#xff0c;如发送数据&#xff…

Java应用一般架构

原文链接&#xff1a;http://www.iteye.com/news/31115 当我们架设一个系统的时候通常需要考虑到如何与其他系统交互&#xff0c;所以我们首先需要知道各种系统之间是如何交互的&#xff0c;使用何种技术实现。 1. 不同系统不同语言之间的交互 现在我们常见的不同系统不同语…

Mac MongoDB未正常关闭导致重启失败

你可以删除掉mongod.lock文件&#xff0c;然后重新启动&#xff0c;如果还是不可以&#xff0c;你可以查看一下进程&#xff0c;然后杀掉&#xff1a; ps -aef | grep mongo sudo kill 1076 再重启数据库即可。

powerdns与nginx结合实现以域名和IP方式访问web服务器80端口时分别跳转到不同页面...

1.powerdns设置 2.内部网站介绍 web服务器采用nginx&#xff0c;内网dns采用powerdns. 想实现的功能如下 通过ip访问时跳转到A页面&#xff0c;通过域名访问时&#xff0c;让其跳转到B页面。两种方式的端口均为80. 页面A对应的nginx配置 server { listen 80; …

java代码块是对象吗_面向对象(Java中普通代码块,构造代码块,静态代码块区别及代码示例)...

//静态代码块:在java中使用static关键字声明的代码块。静态块用于初始化类&#xff0c;为类的属性初始化。每个静态代码块只会执行一次。由于JVM在加载类时会执行静态代码块&#xff0c;所以静态代码块先于主方法执行。//如果类中包含多个静态代码块&#xff0c;那么将按照&quo…

Android app 应用签名

为什么要签名&#xff1f; 这个要从Android的系统设计来解释。 ---Android系统中的每个应用都是一个用户&#xff0c;应用的包名&#xff08;清单文件中 package的值&#xff09;就是用户名。 当一个已安装的应用A和一个正要安装的应用B&#xff0c;它们的包名相同&#xff…

[.Net线程处理系列]专题五:线程同步——事件构造

引言&#xff1a; 其实这部分内容应该是属于专题四&#xff0c;因为这篇也是讲关于线程同步的&#xff0c;但是由于考虑到用户的阅读习惯问题&#xff0c;因为文章太长了&#xff0c;很多人不是很愿意看包括我也是这样的&#xff0c;同时也有和我说可以把代码弄成折叠的&#x…

闪屏页面(Splash)开发

业余作品--365安全卫士 ------------------------------------------- 闪屏页面(Splash)&#xff1a;app刚启动时的页面 作用&#xff1a; 1、展示公司品牌logo 2、应用初始化。如游戏app第一次启动初始化数据 3、检测新版本。 4、检测程序合法性。如 招商银行app在启动…

matlab2016b ubuntu命令行安装 + matconvnet的安装

0. 下载安装包 下载的文件有Matlab 2016b Linux64 Crack.rar&#xff0c;R2016b_glnxa64_dvd2.iso&#xff0c;R2016b_glnxa64_dvd1.iso。 1. 拷贝安装文件并上传服务器 在Windows下用虚拟光驱打开&#xff0c;并将R2016b_glnxa64_dvd1.iso和R2016b_glnxa64_dvd2.iso所有内容复…

java 责任链模式 链表_责任链模式的实现及源码中应用

01—责任链模式的实现假设一个出差任务的流程需要审批出差行程和出差报销金额。那么&#xff0c;对应两个部门的审核。我们先定义一个出差任务Task类&#xff1a;然后&#xff0c;我们定义一个抽象的处理类Handler&#xff0c;其中具体的处理方法Handle交给子类去实现。然后&am…

php setcookie 过期,php cookie怎么设置过期时间?

PHP中可以使用setcookie()函数设置cookie的过期时间。语法为“setcookie(name,value,expire,path,domain,secure)”&#xff1b;其中expire参数用于指定cookie的有效期&#xff0c;即过期时间戳。setcookie() 函数向客户端发送一个 HTTP cookie。cookie 是由服务器发送到浏览器…

jQuery Mobile动态刷新页面样式

见 百度经验 http://jingyan.baidu.com/article/7f766dafbc18f24101e1d014.html JQM里面当我们更新了某些页面标签(如: listview, radiobuttons, checkboxes, select menus)里的数据时,必须做refresh操作. 为什么必须做refresh操作操作呢?因为JQM在做页面渲染的时候,为了使样…

R-CNN论文翻译

R-CNN论文翻译Rich feature hierarchies for accurate object detection and semantic segmentation用于精确物体定位和语义分割的丰富特征层次结构2017-11-29摘要过去几年&#xff0c;在权威数据集PASCAL上&#xff0c;物体检测的效果已经达到一个稳定水平。效果最好的方法是融…

sass、gulp应用

Sass介绍n CSS 不是一个编程语言&#xff0c;可以用它来开发网页样式&#xff0c;但是没有办法用它进行编程。SASS 的出现&#xff0c;让 CSS 实现了通过代码编程来实现的方式。n SASS 是一种 CSS 开发工具&#xff0c;提供了许多便利的写法&#xff0c;让CSS 的处理实现了可编…