Java多线程-锁的区别与使用
锁类型
可中断锁
- 在等待获取锁过程中可中断
- Lock就是可中断锁
公平锁/非公平锁
- 公平锁是指多个线程按照申请锁的顺序来获取锁。
- 非公平锁是指多个线程获取锁的顺序并不是按照申请锁的顺序,有可能后申请的线程比先申请的线程优先获取锁。有可能,会造成优先级反转或者饥饿现象。
- 对于ReentrantLock而言,通过构造函数指定该锁是否是公平锁,默认是非公平锁。非公平锁的优点在于吞吐量比公平锁大。
- 对于Synchronized而言,也是一种非公平锁。由于其并不像ReentrantLock是通过AQS的来实现线程调度,所以并没有任何办法使其变成公平锁。
可重入锁
- 可重入锁又名递归锁,是指在同一个线程在外层方法获取锁的时候,在进入内层方法会自动获取锁。
- 对于Java ReentrantLock而言, 他的名字就可以看出是一个可重入锁,其名字是Re entrant Lock重新进入锁。
- 对于Synchronized而言,也是一个可重入锁。可重入锁的一个好处是可一定程度避免死锁。
synchronized void setA() throws Exception{
Thread.sleep(1000);
setB();
}
synchronized void setB() throws Exception{
Thread.sleep(1000);
}
独享锁/共享锁
- 独享锁是指该锁一次只能被一个线程所持有。
- 共享锁是指该锁可被多个线程所持有。
- 对于Java ReentrantLock而言,其是独享锁。但是对于Lock的另一个实现类ReadWriteLock,其读锁是共享锁,其写锁是独享锁。
- 读锁的共享锁可保证并发读是非常高效的,读写,写读 ,写写的过程是互斥的。
- 独享锁与共享锁也是通过AQS来实现的,通过实现不同的方法,来实现独享或者共享。
- Synchronized是独享锁。
互斥锁/读写锁
- 上面讲的独享锁/共享锁就是一种广义的说法,互斥锁/读写锁就是具体的实现。
- 互斥锁在Java中的具体实现就是ReentrantLock
- 读写锁在Java中的具体实现就是ReadWriteLock
乐观锁/悲观锁
- 乐观锁与悲观锁不是指具体的什么类型的锁,而是指看待并发同步的角度。
- 悲观锁认为对于同一个数据的并发操作,一定是会发生修改的,哪怕没有修改,也会认为修改。因此对于同一个数据的并发操作,悲观锁采取加锁的形式。悲观的认为,不加锁的并发操作一定会出问题。
- 乐观锁则认为对于同一个数据的并发操作,是不会发生修改的。在更新数据的时候,会采用尝试更新,不断重新的方式更新数据。乐观的认为,不加锁的并发操作是没有事情的。
- 从上面的描述我们可以看出,悲观锁适合写操作非常多的场景,乐观锁适合读操作非常多的场景,不加锁会带来大量的性能提升。
- 悲观锁在Java中的使用,就是利用各种锁。
- 乐观锁在Java中的使用,是无锁编程,常常采用的是CAS算法,典型的例子就是原子类,通过CAS自旋实现原子操作的更新。
分段锁
- 分段锁其实是一种锁的设计,并不是具体的一种锁,对于ConcurrentHashMap而言,其并发的实现就是通过分段锁的形式来实现高效的并发操作。
- 分段锁的设计目的是细化锁的粒度,当操作不需要更新整个数组的时候,就仅仅针对数组中的一项进行加锁操作。
偏向锁/轻量级锁/重量级锁
- 这三种锁是指锁的状态,并且是针对Synchronized。在Java 5通过引入锁升级的机制来实现高效Synchronized。这三种锁的状态是通过对象监视器在对象头中的字段来表明的。
- 偏向锁是指一段同步代码一直被一个线程所访问,那么该线程会自动获取锁。降低获取锁的代价。
- 轻量级锁是指当锁是偏向锁的时候,被另一个线程所访问,偏向锁就会升级为轻量级锁,其他线程会通过自旋的形式尝试获取锁,不会阻塞,提高性能。
- 重量级锁是指当锁为轻量级锁的时候,另一个线程虽然是自旋,但自旋不会一直持续下去,当自旋一定次数的时候,还没有获取到锁,就会进入阻塞,该锁膨胀为重量级锁。重量级锁会让其他申请的线程进入阻塞,性能降低。
自旋锁
- 自旋锁原理非常简单,如果持有锁的线程能在很短时间内释放锁资源,那么那些等待竞争锁的线程就不需要做内核态和用户态之间的切换进入阻塞挂起状态,它们只需要等一等(自旋),等持有锁的线程释放锁后即可立即获取锁,这样就避免用户线程和内核的切换的消耗。
- 但是线程自旋是需要消耗cup的,说白了就是让cup在做无用功,如果一直获取不到锁,那线程也不能一直占用cup自旋做无用功,所以需要设定一个自旋等待的最大时间。
- 如果持有锁的线程执行的时间超过自旋等待的最大时间扔没有释放锁,就会导致其它争用锁的线程在最大等待时间内还是获取不到锁,这时争用线程会停止自旋进入阻塞状态。
Synchronized与Static Synchronized
区别
static synchronized方法是类锁,synchronized方法是对象锁
synchronized相当于 this.synchronized,static synchronized相当于Something.synchronized
举例
pulbic class Test(){
public synchronized void A(){}
public synchronized void B(){}
public static synchronized void cA(){}
public static synchronized void cB(){}
}
新建两个实例,x和y
1 x.A()与x.B()
2 x.A()与y.A()
3 x.cA()与y.cB()
4 x.A()与Test.cA()
四种情况哪组方法何以被多个以上线程同时访问?
- 情况1:同一个实例上锁肯定不行
- 情况2:是针对不同实例的,因此可以同时被访问
- 情况3:因为static synchronized为类锁,所以不同实例之间仍然会被限制
- 情况4:可以,类锁和实例锁互不干扰
Lock
定义
Lock是一个接口
public interface Lock {
void lock();
void lockInterruptibly() throws InterruptedException;
boolean tryLock();
boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
void unlock();
Condition newCondition();
}
lock()
、tryLock()
、tryLock(long time, TimeUnit unit)
和lockInterruptibly()
是用来获取锁的。unLock()
方法是用来释放锁的。
四种获取Lock的方法区别
lock()
平常使用得最多的一个方法,就是用来获取锁。如果锁已被其他线程获取,则进行等待。
使用Lock必须在try{}catch{}
块中进行,并且将释放锁的操作放在finally
块中进行,以保证锁一定被被释放,防止死锁的发生。
Lock lock = ...;
lock.lock();
try{
//处理任务
}catch(Exception ex){
}finally{
lock.unlock(); //释放锁
}
tryLock()
tryLock()
有返回值的,它表示用来尝试获取锁,如果获取成功,则返回true,如果锁已被其他线程获取,则返回false。
这个方法会立即返回,在拿不到锁时也不会一直在那等待。
Lock lock = ...;
if(lock.tryLock()) {
try{
//处理任务
}catch(Exception ex){
}finally{
lock.unlock(); //释放锁
}
}else {
//如果不能获取锁,则直接做其他事情
}
tryLock(long time, TimeUnit unit)
此方法在拿不到锁时会等待一定的时间,在时间期限之内如果还拿不到锁,就返回false。如果如果一开始拿到锁或者在等待期间内拿到了锁,则返回true。
lockInterruptibly()
方法比较特殊,当通过这个方法去获取锁时,如果线程正在等待获取锁,则这个线程能够响应中断,即中断线程的等待状态。也就使说,当两个线程同时通过lock.lockInterruptibly()
想获取某个锁时,假若此时线程A获取到了锁,而线程B还在等待,那么对线程B调用threadB.interrupt()方法中断线程B的等待过程。
lockInterruptibly()
当通过lockInterruptibly()方法获取某个锁时,如果不能获取到,只有进行等待的情况下,是可以响应中断的。
而用synchronized修饰的话,当一个线程处于等待某个锁的状态,是无法被中断的,只有一直等待下去。
当一个线程获取了锁之后,是不会被interrupt()方法中断的。单独调用interrupt()方法不能中断正在运行过程中的线程,只能中断阻塞过程中的线程。
lockInterruptibly()
的声明中抛出了异常,所以lock.lockInterruptibly()
必须放在try块中或者在调用lockInterruptibly()
的方法外声明抛出InterruptedException。
public void method() throws InterruptedException {
lock.lockInterruptibly();
try {
//.....
}
finally {
lock.unlock();
}
}
synchronized与Lock的区别
Java多线程-锁的区别与使用的更多相关文章
- Java多线程--锁的优化
Java多线程--锁的优化 提高锁的性能 减少锁的持有时间 一个线程如果持有锁太长时间,其他线程就必须等待相应的时间,如果有多个线程都在等待该资源,整体性能必然下降.所有有必要减少单个线程持有锁的时间 ...
- synchronized与static synchronized 的差别、synchronized在JVM底层的实现原理及Java多线程锁理解
本Blog分为例如以下部分: 第一部分:synchronized与static synchronized 的差别 第二部分:JVM底层又是怎样实现synchronized的 第三部分:Java多线程锁 ...
- Java多线程——锁
Java多线系列文章是Java多线程的详解介绍,对多线程还不熟悉的同学可以先去看一下我的这篇博客Java基础系列3:多线程超详细总结,这篇博客从宏观层面介绍了多线程的整体概况,接下来的几篇文章是对多线 ...
- Java 多线程 锁 存款 取款
http://jameswxx.iteye.com/blog/806968 最近想将java基础的一些东西都整理整理,写下来,这是对知识的总结,也是一种乐趣.已经拟好了提纲,大概分为这几个主题: ja ...
- Java多线程——锁概念与锁优化
为了性能与使用的场景,Java实现锁的方式有非常多.而关于锁主要的实现包含synchronized关键字.AQS框架下的锁,其中的实现都离不开以下的策略. 悲观锁与乐观锁 乐观锁.乐观的想法,认为并发 ...
- [java多线程] - 锁机制&同步代码块&信号量
在美眉图片下载demo中,我们可以看到多个线程在公用一些变量,这个时候难免会发生冲突.冲突并不可怕,可怕的是当多线程的情况下,你没法控制冲突.按照我的理解在java中实现同步的方式分为三种,分别是:同 ...
- 详解Java多线程锁之synchronized
synchronized是Java中解决并发问题的一种最常用的方法,也是最简单的一种方法. synchronized的四种使用方式 修饰代码块:被修饰的代码块称为同步语句块,其作用的范围是大括号{}括 ...
- Java——多线程锁的那些事
引入 Java提供了种类丰富的锁,每种锁因其特性的不同,在适当的场景下能够展现出非常高的效率. 下面先带大家来总体预览一下锁的分类图 1.乐观锁 VS 悲观锁 乐观锁与悲观锁是一种广义上的概念,体现了 ...
- java多线程-锁
自 Java 5 开始,java.util.concurrent.locks 包中包含了一些锁的实现,因此你不用去实现自己的锁了.但是你仍然需要去了解怎样使用这些锁. 一个简单的锁 让我们从 java ...
随机推荐
- Dwango Programming Contest 6th E 题解
题目大意 你有一条区间\([0, X)\),并且有一个数组\(L_1, ..., L_n\).对于任意\(1 \leq i \leq n\),你可以指定一个非负整数\(0 \leq j_i \leq ...
- eclipse 搭建连接 activemq
今天我特地写下笔记,希望可以完全掌握这个东西,也希望可以帮助到任何想对学习这个东西的同学. 1.下载activemq压缩包,并解压(如果需要下载请看文章尾部附录) 2.进入bin文件夹,(64位电脑就 ...
- uni-app微信小程序登录授权
微信小程序授权是非常简单和常用的功能,但为了方便,还是在此记录一下要点: 首先是需要用到一个授权按钮来触发获取用户信息授权: 关键在于 open-type 为 getUserInfo , 然后有个@g ...
- 【opencv】学习笔记
安装 此笔记仅对python36实用 OpenCV装3.4.1.15 指令:pip install -i https://pypi.tuna.tsinghua.edu.cn/simple opencv ...
- Day2 之 元组tuple
tuple 元组 也是有序列表 ,与list非常相似,但是tuple一旦初始化就不能修改. name = ('a','b',1,2,3,True) tuple ...
- Jackson:我是最牛掰的 Java JSON 解析器(有点虚)
在当今的编程世界里,JSON 已经成为将信息从客户端传输到服务器端的首选协议,可以好不夸张的说,XML 就是那个被拍死在沙滩上的前浪. 很不幸的是,JDK 没有 JSON 库,不知道为什么不搞一下.L ...
- CDH集群spark-shell执行过程分析
目的 刚入门spark,安装的是CDH的版本,版本号spark-core_2.11-2.4.0-cdh6.2.1,部署了cdh客户端(非集群节点),本文主要以spark-shell为例子,对在cdh客 ...
- Windows单机安装hadoop
版本信息 Hadoop 3.2.0 java version "1.8.0_201" Windows 7专业版,64位 安装过程 jdk安装 下载jdk,解压到目录,D:\Java ...
- CSS3全览_动画+滤镜
CSS3全览_动画+滤镜 目录 CSS3全览_动画+滤镜 1. 列表和生成的内容 2. 变形 3. 过渡 4. 动画 5. 滤镜, 混合, 裁剪和遮罩 6. 针对特定媒体的样式 作者: https:/ ...
- 一位年薪30w软件测试员的职业规划
先抛出一个观点: 那些,担心30岁后,35岁后,40岁后,无路可走的:基本属于能力不够.或者思维太局限.总之,瞎担心/不长进. 具体,见下面正文 曾经,在16年,写过一系列的软件测试从业者职业成长文章 ...