JAVA并发包——锁
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并发包——锁的更多相关文章
- 深入浅出Java并发包—锁机制(三)
接上文<深入浅出Java并发包—锁机制(二)> 由锁衍生的下一个对象是条件变量,这个对象的存在很大程度上是为了解决Object.wait/notify/notifyAll难以使用的问题. ...
- 深入浅出Java并发包—锁机制(二)
接上文<深入浅出Java并发包—锁机制(一) > 2.Sync.FairSync.TryAcquire(公平锁) 我们直接来看代码 protected final boolean tr ...
- 深入浅出Java并发包—锁机制(一)
前面我们看到了Lock和synchronized都能正常的保证数据的一致性(上文例子中执行的结果都是20000000),也看到了Lock的优势,那究竟他们是什么原理来保障的呢?今天我们就来探讨下Jav ...
- 深入浅出Java并发包—锁(Lock)VS同步(synchronized)
今天我们来探讨一下Java中的锁机制.前面我们提到,在JDK1.5之前只能通过synchronized关键字来实现同步,这个前面我们已经提到是属于独占锁,性能并不高,因此JDK1.5之后开始借助JNI ...
- java并发包&线程池原理分析&锁的深度化
java并发包&线程池原理分析&锁的深度化 并发包 同步容器类 Vector与ArrayList区别 1.ArrayList是最常用的List实现类,内部是通过数组实现的, ...
- Java并发包——线程同步和锁
Java并发包——线程同步和锁 摘要:本文主要学习了Java并发包里有关线程同步的类和锁的一些相关概念. 部分内容来自以下博客: https://www.cnblogs.com/dolphin0520 ...
- Java并发包下锁学习第一篇:介绍及学习安排
Java并发包下锁学习第一篇:介绍及学习安排 在Java并发编程中,实现锁的方式有两种,分别是:可以使用同步锁(synchronized关键字的锁),还有lock接口下的锁.从今天起,凯哥将带领大家一 ...
- Java并发包下锁学习第二篇Java并发基础框架-队列同步器介绍
Java并发包下锁学习第二篇队列同步器 还记得在第一篇文章中,讲到的locks包下的类结果图吗?如下图: 从图中,我们可以看到AbstractQueuedSynchronizer这个类很重要(在本 ...
- Java并发包源码学习系列:ReentrantLock可重入独占锁详解
目录 基本用法介绍 继承体系 构造方法 state状态表示 获取锁 void lock()方法 NonfairSync FairSync 公平与非公平策略的差异 void lockInterrupti ...
随机推荐
- 【入门】ZooKeeper 相关概念总结
1. 前言 相信大家对 ZooKeeper 应该不算陌生.但是你真的了解 ZooKeeper 到底有啥用不?如果别人/面试官让你给他讲讲对于 ZooKeeper 的认识,你能回答到什么地步呢? 拿我自 ...
- opencv-python imread、imshow浏览目录下的图片文件
☞ ░ 前往老猿Python博文目录 ░ 一.几个知识点 1.1.使用Python查找目录下的文件 具体请参考<Python正则表达式re模块和os模块实现文件搜索模式匹配>. 1.2.o ...
- PyQt(Python+Qt)学习随笔:富文本编辑器QTextEdit功能详解
专栏:Python基础教程目录 专栏:使用PyQt开发图形界面Python应用 专栏:PyQt入门学习 老猿Python博文目录 一.概述 QTextEdit是一个高级的所见即所得的文档查看器和编辑器 ...
- 第8.31节 Python中使用__delattr__清除属性数据
一. 引言 在前面几节我们介绍了__ getattribute__方法和__setattr__方法,分别实现了实例属性的查询和修改(含定义即新增),作为Python中数据操作必不可少的三剑客get.s ...
- C#中SQL SERVER 2008字符数据类型使用心得
一.尽可能使用Varchar,少使用或者不使用Char字符类型 因为char类型输入的数据长度达不到设计长度,会用空格补足,下面是数据表设计图: 下面是编辑前200行的图: 凡是输入的数据长度达不到设 ...
- leetcode(三)——2020.05.31
(上周7道题完成) 本周leetcode题目(from leetcode hot100): 15 17 19 21 33 94 42 额外完成: 22(回溯), 8, 31,200
- socket和http有什么区别?
socket是网络传输层的一种技术,跟http有本质的区别,http是应用层的一个网络协议.使用socket技术理论上来讲, 按照http的规范,完全可以使用socket来达到发送http请求的目的, ...
- JavaSE19-IO特殊流和Properties集合
1.IO特殊操作流 1.1 标准输入流 System类中有两个静态的成员变量 public static final InputStream in:标准输入流.通常该流对应于键盘输入或由主机环境或用户 ...
- 2020-2021-1 20209307《Linux内核原理与分析》第七周作业
这个作业属于哪个课程 <2020-2021-1Linux内核原理与分析)> 这个作业要求在哪里 <2020-2021-1Linux内核原理与分析第七周作业> 这个作业的目标 & ...
- swig python dynamic module does not define init function
example_module = Extension('_example', sources=['example_wrap.c', 'example.c'], ) setup (name = 'exa ...