1.java多线程中,可以使用synchronized关键字来实现线程间的同步互斥工作,其实还有个更优秀的机制来完成这个同步互斥的工作——Lock对象,主要有2种锁:重入锁和读写锁,它们比synchronized具有更强大的功能,并且有嗅探锁定、多路分支等功能。

2.ReentrantLock(重入锁)

重入锁,在需要进行同步的代码部分加上锁定,但不要忘记最后一定要释放锁定,否则会造成锁永远无法释放,其他线程永远进不来的结果(使用起来跟synchronized很像,并且,在jdk1.8之前,ReentrantLock比synchronized性能好,jdk1.8对synchronized做了优化,性能接近了。但是ReentrantLock比synchronized灵活)

代码示例:

 1 package lock020;
2
3 import java.util.concurrent.locks.Lock;
4 import java.util.concurrent.locks.ReentrantLock;
5
6 public class UseReentrantLock {
7
8 private Lock lock = new ReentrantLock();
9
10 public void method1(){
11 try {
12 lock.lock();
13 System.out.println("当前线程:" + Thread.currentThread().getName() + "进入method1..");
14 Thread.sleep(1000);
15 System.out.println("当前线程:" + Thread.currentThread().getName() + "退出method1..");
16 Thread.sleep(1000);
17 } catch (InterruptedException e) {
18 e.printStackTrace();
19 } finally {
20
21 lock.unlock();
22 }
23 }
24
25 public static void main(String[] args) {
26
27 final UseReentrantLock ur = new UseReentrantLock();
28 Thread t1 = new Thread(new Runnable() {
29 @Override
30 public void run() {
31 ur.method1();
32 }
33 }, "t1");
34
35 t1.start();
36
37 Thread t2 = new Thread(new Runnable() {
38 @Override
39 public void run() {
40 ur.method1();
41 }
42 }, "t2");
43
44 t2.start();
45
46 try {
47 Thread.sleep(10);
48 } catch (InterruptedException e) {
49 e.printStackTrace();
50 }
51 //System.out.println(ur.lock.getQueueLength());
52 }
53
54
55 }

执行以后,可以发现,t1和t2是串行执行method1的

3.ReentrantLock锁的等待与通知

synchronized关键字里,有Object的wait()方法和notify()/notifyAll()方法进行多线程之间的工作协调。而同样的,Lock也有自己的等待/通知类,它就是Condition。这个Condition一定是针对某一把具体的锁的,就是说,只有有锁的基础之才会产生Condition

代码实现:

 1 package lock020;
2
3 import java.util.concurrent.locks.Condition;
4 import java.util.concurrent.locks.Lock;
5 import java.util.concurrent.locks.ReentrantLock;
6
7 public class UseCondition {
8
9 private Lock lock = new ReentrantLock();
10 private Condition condition = lock.newCondition();
11
12 public void method1(){
13 try {
14 lock.lock();
15 System.out.println("当前线程:" + Thread.currentThread().getName() + "进入等待状态..");
16 Thread.sleep(3000);
17 System.out.println("当前线程:" + Thread.currentThread().getName() + "释放锁..");
18 condition.await(); // Object wait,释放锁
19 System.out.println("当前线程:" + Thread.currentThread().getName() +"继续执行...");
20 } catch (Exception e) {
21 e.printStackTrace();
22 } finally {
23 lock.unlock();
24 }
25 }
26
27 public void method2(){
28 try {
29 lock.lock();
30 System.out.println("当前线程:" + Thread.currentThread().getName() + "进入..");
31 Thread.sleep(3000);
32 System.out.println("当前线程:" + Thread.currentThread().getName() + "发出唤醒..");
33 condition.signal(); //Object notify
34 } catch (Exception e) {
35 e.printStackTrace();
36 } finally {
37 lock.unlock();
38 }
39 }
40
41 public static void main(String[] args) {
42
43 final UseCondition uc = new UseCondition();
44 Thread t1 = new Thread(new Runnable() {
45 @Override
46 public void run() {
47 uc.method1();
48 }
49 }, "t1");
50 Thread t2 = new Thread(new Runnable() {
51 @Override
52 public void run() {
53 uc.method2();
54 }
55 }, "t2");
56
57 t1.start();
58 t2.start();
59 }
60
61
62
63 }

以上代码,实现了wait/nofity的功能

ps:不同的线程之间,可以用不同的Condition对象来进行通信。例如t1唤醒t2用 Condition1,t3唤醒t4用Condition2,这也是比wait/notify灵活的地方

3.公平锁和非公平锁

公平锁的作用就是严格按照线程启动的顺序来执行的,不允许其他线程插队执行的;而非公平锁是允许插队的。(默认是非公平锁)

可以通过构造方法指定参数是ture(公平)或者false(非公平),一般说来,非公平锁比公平锁性能要好,因为公平锁要维护顺序

4.ReentrantLock锁与synchronized的区别

类别 synchronized Lock
存在层次 Java的关键字,在jvm层面上 是一个类
锁的释放 1、以获取锁的线程执行完同步代码,释放锁 2、线程执行发生异常,jvm会让线程释放锁 在finally中必须释放锁,不然容易造成线程死锁
锁的获取 假设A线程获得锁,B线程等待。如果A线程阻塞,B线程会一直等待 分情况而定,Lock有多个锁获取的方式,具体下面会说道,大致就是可以尝试获得锁,线程可以不用一直等待
锁状态 无法判断 可以判断
锁类型 可重入 不可中断 非公平 可重入 可判断 可公平(两者皆可)
性能 少量同步 大量同步

5.ReenTrantReadWriteLock(读写锁)

核心其实就是实现读写分离。在高并发的情况下,尤其是读多写少的情况下,性能远高于重入锁

之前的ReentrantLock和synchronized的使用时,同一时间内,只能一个线程访问被锁定的代码。读写锁不同,其本质是2个锁,即读锁和写锁。在读锁下,多个线程可以并发访问,但是在写锁下,只能串行访问

口诀:读读共享,写写互斥,读写互斥

代码示例:

 1 package lock021;
2
3 import java.util.concurrent.locks.ReentrantReadWriteLock;
4 import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
5 import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;
6
7 public class UseReentrantReadWriteLock {
8
9 private ReentrantReadWriteLock rwLock = new ReentrantReadWriteLock();
10 private ReadLock readLock = rwLock.readLock();
11 private WriteLock writeLock = rwLock.writeLock();
12
13 public void read(){
14 try {
15 readLock.lock();
16 System.out.println("当前线程:" + Thread.currentThread().getName() + "进入...");
17 Thread.sleep(3000);
18 System.out.println("当前线程:" + Thread.currentThread().getName() + "退出...");
19 } catch (Exception e) {
20 e.printStackTrace();
21 } finally {
22 readLock.unlock();
23 }
24 }
25
26 public void write(){
27 try {
28 writeLock.lock();
29 System.out.println("当前线程:" + Thread.currentThread().getName() + "进入...");
30 Thread.sleep(3000);
31 System.out.println("当前线程:" + Thread.currentThread().getName() + "退出...");
32 } catch (Exception e) {
33 e.printStackTrace();
34 } finally {
35 writeLock.unlock();
36 }
37 }
38
39 public static void main(String[] args) {
40
41 final UseReentrantReadWriteLock urrw = new UseReentrantReadWriteLock();
42
43 Thread tr1 = new Thread(new Runnable() {
44 @Override
45 public void run() {
46 urrw.read();
47 }
48 }, "t1");
49 Thread tr2 = new Thread(new Runnable() {
50 @Override
51 public void run() {
52 urrw.read();
53 }
54 }, "t2");
55 Thread tw3 = new Thread(new Runnable() {
56 @Override
57 public void run() {
58 urrw.write();
59 }
60 }, "t3");
61 Thread tw4 = new Thread(new Runnable() {
62 @Override
63 public void run() {
64 urrw.write();
65 }
66 }, "t4");
67
68 tr1.start();
69 tr2.start();
70
71 tw3.start();
72 tw4.start();
73
74 }
75 }

模拟代码可发现:

如果是都是读操作,基本是同时进行的

如果有写操作,是要锁定的

6.锁的优化

(1)避免死锁

(2)减小锁的持有时间

(3)减小锁的粒度

(4)锁的分离

(5)尽量使用无锁的操作,如原子操作(Atomic类系列)、volatile关键字

7.分布式锁的概念

2台机器都部署了项目,显然,运行的jvm是不同的,如果t1线程在机器A,t2线程在机器B,同时要访问同一段锁定的代码块

显然,jvm的锁机制是无法处理这种情况的,这时候要考虑第三方帮助实现,如zookkeeper

JAVA并发包——锁的更多相关文章

  1. 深入浅出Java并发包—锁机制(三)

    接上文<深入浅出Java并发包—锁机制(二)>  由锁衍生的下一个对象是条件变量,这个对象的存在很大程度上是为了解决Object.wait/notify/notifyAll难以使用的问题. ...

  2. 深入浅出Java并发包—锁机制(二)

    接上文<深入浅出Java并发包—锁机制(一)  >  2.Sync.FairSync.TryAcquire(公平锁) 我们直接来看代码 protected final boolean tr ...

  3. 深入浅出Java并发包—锁机制(一)

    前面我们看到了Lock和synchronized都能正常的保证数据的一致性(上文例子中执行的结果都是20000000),也看到了Lock的优势,那究竟他们是什么原理来保障的呢?今天我们就来探讨下Jav ...

  4. 深入浅出Java并发包—锁(Lock)VS同步(synchronized)

    今天我们来探讨一下Java中的锁机制.前面我们提到,在JDK1.5之前只能通过synchronized关键字来实现同步,这个前面我们已经提到是属于独占锁,性能并不高,因此JDK1.5之后开始借助JNI ...

  5. java并发包&线程池原理分析&锁的深度化

          java并发包&线程池原理分析&锁的深度化 并发包 同步容器类 Vector与ArrayList区别 1.ArrayList是最常用的List实现类,内部是通过数组实现的, ...

  6. Java并发包——线程同步和锁

    Java并发包——线程同步和锁 摘要:本文主要学习了Java并发包里有关线程同步的类和锁的一些相关概念. 部分内容来自以下博客: https://www.cnblogs.com/dolphin0520 ...

  7. Java并发包下锁学习第一篇:介绍及学习安排

    Java并发包下锁学习第一篇:介绍及学习安排 在Java并发编程中,实现锁的方式有两种,分别是:可以使用同步锁(synchronized关键字的锁),还有lock接口下的锁.从今天起,凯哥将带领大家一 ...

  8. Java并发包下锁学习第二篇Java并发基础框架-队列同步器介绍

    Java并发包下锁学习第二篇队列同步器 还记得在第一篇文章中,讲到的locks包下的类结果图吗?如下图: ​ 从图中,我们可以看到AbstractQueuedSynchronizer这个类很重要(在本 ...

  9. Java并发包源码学习系列:ReentrantLock可重入独占锁详解

    目录 基本用法介绍 继承体系 构造方法 state状态表示 获取锁 void lock()方法 NonfairSync FairSync 公平与非公平策略的差异 void lockInterrupti ...

随机推荐

  1. 对称加密之---AES加密

    工作中常会需要让数据传输前进行加密处理.这次用到的是AES加密.AES加密中,需要注意到坑还是挺多的.对AES也进行了一番了解,发现里面的东西真的是注意的太多了.今天只是整理了一种简单的加密格式,工作 ...

  2. FOFA链接爬虫爬取fofa spider

    之前一直是用的github上别人爬取fofa的脚本,前两天用的时候只能爬取第一页的链接了,猜测是fofa修改了一部分规则(或者是我不小心删除了一部分文件导致不能正常运行了) 于是重新写了一下爬取fof ...

  3. Scrum 冲刺第三天

    一.每日站立式会议 1.会议内容 1)进行每日工作汇报 张博愉: 昨天已完成的工作:博客编写.spring boot学习 今日工作计划:将项目代码更新到最新版本 工作中遇到的困难:各成员的环境不一样, ...

  4. 廖雪峰官网学习js 数组

    indexOf( )    某字符的位置 slice 相当于string 的substring 切片 a = ['a','b',1,2,3] (5) ["a", "b&q ...

  5. sql注入之union注入

    联合查询注入利用的前提: 必须要有回显 联合查询过程: 判断是否存在注入点 判断是什么类型注入(字符型or数字型) 判断闭合方式 查询列数个数(order by) 5, 获得数据库名 获得表名 获得字 ...

  6. 基于WSL2 的 Docker Desktop 启动时 Failed to set version to docker-desktop: exit code: -1的解决方法

    在Windows 10 的 2004 版本  中, 启用 使用Docker Desktop 时 发现  根本无法启动, 偶尔 或者频繁的出错: System.InvalidOperationExcep ...

  7. Java JVM——2.类加载器子系统

    概述 类加载器子系统在Java JVM中的位置 类加载器子系统的具体实现 类加载器子系统的作用 ① 负责从文件系统或者网络中加载.class文件,Class 文件在文件开头有特定的文件标识. ② Cl ...

  8. Python开发:一个直播弹幕机器人诞生过程,自动发送弹幕

    前言 本文的文字及图片来源于网络,仅供学习.交流使用,不具有任何商业用途,如有问题请及时联系我们以作处理. Python爬取B站弹幕视频讲解 https://www.bilibili.com/vide ...

  9. mini-web框架-装饰器-总结2(5.3.2)

    @ 目录 1.说明 2.代码 关于作者 1.说明 多级装饰器嵌套 带参数的装饰器 这里打印print(index) 会在函数定义的时候@test(222) 就被调用,返回一个test2继续装饰 2.代 ...

  10. python线性回归

    一.理论基础 1.回归公式 对于单元的线性回归,我们有:f(x) = kx + b 的方程(k代表权重,b代表截距). 对于多元线性回归,我们有: 或者为了简化,干脆将b视为k0·x0,,其中k0为1 ...