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 ...
随机推荐
- vue-父子组件传参以及无限级评论
vue父子组件的使用 <template> <div> <zi :data="data" /> </div> </templa ...
- Abp(net core)+easyui+efcore实现仓储管理系统——出库管理之七(五十六)
abp(net core)+easyui+efcore实现仓储管理系统目录 abp(net core)+easyui+efcore实现仓储管理系统--ABP总体介绍(一) abp(net core)+ ...
- 第9.4节 Python中用readline读取二进制文件方式打开文件
在<第9.3节 Python的文件内容读取:readline>中介绍了使用readline读取文件的处理,readline除了使用文本文件方式打开文件读外,也可以读取二进制方式打开的文件, ...
- PyQt(Python+Qt)学习随笔:model/view架构中的QStandardItemModel使用案例
老猿Python博文目录 专栏:使用PyQt开发图形界面Python应用 老猿Python博客地址 1.案例说明 在应用中展示指定目录的图标文件的文件名和图标,界面就是一个简单的窗口上面放置一名为li ...
- CTFD平台部署自制题目指北(灌题)
给实验室同学搭建的CTFD平台用于内部训练和CTF的校赛,为了循序渐进当然是先内部出一些简单入门的题目,但是网上大部分关于CTFD平台的都只是部署,而关于题目放置的内容却很少,虽然这个过程比较简单,但 ...
- Server returns invalid timezone. Go to 'Advanced' tab and set 'serverTimezone' property manually.
用pycharm连接mysql报错 改变serverTimezone 改了之后确实可以连接上mysql数据库
- 网络层-network layer(下):网络互连、子网掩码计算方法、Ipv4报头解析
第五章 网络层-Network Layer(下) 上一章讲了网络层的任务.提供的两种服务.五个重要的路由算法.以及网络层的拥塞控制和服务质量问题.这一部分主要讲一讲网络互连问题和Internet的网络 ...
- LibreOj #539. 「LibreOJ NOIP Round #1」旅游路线
题目链接 做完这道题,我深知当一个问题复杂度过高的时候,把一些可以分离的操作都分散开,可以大幅度降低复杂度..... 发现无论有多少钱,每到一个点后扩展到的距离被限制在 \(min(C, c[i])\ ...
- 搞定MySQL安装难安装贵问题
背景 本方案解决了windows下安装MySQL过程繁琐的问题. 是真正的免安装绿色方法,不用配环境变量,不用执行install命令,不用配置my.ini文件. 步骤 下载 下载mysql-8.0.2 ...
- 使用collectd+influxdb+grafna监控进程的健康状态
一,前言 本文将介绍如何使用collectd+influxdb+grafna进行进程的监控,监控项为:进程健康状态. 思路为:使用collectd的processes插件进行程序进程的监控,储存到in ...