发布于2021-03-13 14:06 阅读(675) 评论(0) 点赞(26) 收藏(0)
之前说了线程同步机制Synchronize锁,其实除此之外还有一种JUC的Lock锁也能实现线程同步。而且Lock实现类ReentrantLock相比Synchronize有更大的灵活性,更加丰富,更是适合大多场景的使用。
先来简单的对比下ReentrantLock和Synchronize吧。
- Synchronsize锁是独占锁,加锁和释放锁都是自动的,只要加上关键字synchronize或者代码块就行。使用起来很简单,但是呢灵活性较差。ReentrantLock也是独占锁,但是它需要手动的加锁(lock等)和释放锁(unlock),使用的起来相对复杂了点,但是灵活性好,且ReentrantLock提供了丰富的方法。
- Synchronsize和ReentrantLock都是可重入锁(可以多次使用锁:举个例子,方法A使用了锁,其实调用B,但是B也使用了锁,这是调用B的时候不用重新获取锁)。但是都是需要释放锁才能让其它线程拿到锁。
- Synchronize一旦拿不到锁,产生了死锁等待状态时,相应不能中断,而ReentrantLock提供了相应中单的锁。
- 最主要的就是ReentrantLock还可以实现公平锁机制。什么叫公平锁呢?也就是在锁上等待时间最长的线程将获得锁的使用权。通俗的理解就是谁排队时间最长谁先执行获取锁。
与Synchronize不同的是,ReentrantLock提供了多个锁,可以根据不同需求处理线程同步问题。下面我们重点介绍下ReentrantLock锁,Synchronize的介绍请查看之前的博客线程不安全+线程死锁+同步。
ReentrantLock是JUC包下的类(java.util.concurrent.locks.ReentrantLock),实现了Lock接口。
ReentrantLock的释放锁都是一样unlock方法,下面主要看下ReentrantLock不同的锁。
不实现线程同步的时候,不加锁效果:
public class ReenTrantLockThread {
public static void main(String[] args) {
ThreadTest threadTest = new ThreadTest();
new Thread(threadTest,"小明").start();
new Thread(threadTest,"小王").start();
}
}
class ThreadTest implements Runnable{
final Lock lock = new ReentrantLock();
@Override
public void run() {
study();
}
public void study(){
for (int i = 0; i < 10; i++) {
System.out.println(Thread.currentThread().getName()+":我正在学习");
}
}
}
结果:
小明和小王疯由cpu调度学习。加了锁之后,让一个人学习完再下一个线程拿锁学习(注意哦,下一个线程不一定是另一个人哦,由cpu调度)
(1)Lock() 这个锁就是普通也是常用的锁,和Synchronize锁差不多,一旦拿到锁之后必须等待释放锁,才能继续拿锁,否则会出现线程死锁,所以使用结束之后一定要释放锁。
注意:为了防止不释放锁,一般将加锁内容放到try里面,然后在finally里面释放锁,这样保证一定会释放锁。
public void study(){
lock.lock();
try { /
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+":我正在学习");
}
}catch (Exception e){
}finally {
lock.unlock()
}
}
结果: 让一个人学习完再下一个线程拿锁学习!!!
(2) tryLock()锁,我叫它尝试锁,它是用来尝试获取锁,如果能获取到那么可以占有锁使用,如果拿不到我们也可以处理其他事物。它是有返回值的,类型boolean,如果拿到了锁就返回true,拿不到就返回false,所以不管怎么的它都会立马返回一个值。
public void study(){
boolean flag = lock.tryLock();
if(flag){
try {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+":我正在学习");
}
}catch (Exception e){
}finally {
lock.unlock();
}
}else {
System.out.println(Thread.currentThread().getName()+":我没拿到锁,那我去看电视了");
}
}
结果:
(3)tryLock(long timeout, TimeUnit unit),用法跟tryLock是一样的,不同的是可以指定等待时间,就是锁我拿锁,如果指定时间后还没拿到锁我就返回false,时间没到那我就继续等待锁释放。
public void study() throws InterruptedException {
boolean flag = lock.tryLock(5000,TimeUnit.MILLISECONDS); // 等待5秒钟拿不到锁就返回false
if(flag){
try {
for (int i = 0; i < 5; i++) {
System.out.println(Thread.currentThread().getName()+":我正在学习");
}
}catch (Exception e){
}finally {
lock.unlock();
}
}else {
System.out.println(Thread.currentThread().getName()+":我没拿到锁,那我去看电视了");
}
}
结果:5秒内成功拿到锁。
我们给线程加上一个sleep,让线程休息总时间超过5秒,
(4)lockInterruptibly()中断锁,使用这个锁可有主动主断线程使用Thread.interrupt()。前提是这个线程用到锁了,在没有用锁的情况下是用不了的。这个不好演示,用法如下:
然后说说ReentrantLock特殊的锁机制,公平锁和非公平锁。
就跟字面上意思差不多,
公平锁意思就是哪个线程排队时间长就让谁优点调度。
非公平锁意思就是不管线程啥时候开始排的队,我就让cpu看心情调度。
使用方法非常简单,只需要在初始化锁的时候加上,true(公平)或者false(不公平)参数。默认就是false
公平锁:
final Lock lock = new ReentrantLock(true);
public void study() throws InterruptedException {
for (int i = 0; i <2 ; i++) {
try {
lock.lock(); // 等待5秒钟拿不到锁就返回false
System.out.println(Thread.currentThread().getName()+":我正在学习");
//Thread.sleep(2000);
}catch (Exception e){
}finally {
lock.unlock();
}
}
}
结果:大家不要挤,人人有份。
非公平锁:
final Lock lock = new ReentrantLock(false);
public void study() throws InterruptedException {
for (int i = 0; i <2 ; i++) {
try {
lock.lock(); // 等待5秒钟拿不到锁就返回false
System.out.println(Thread.currentThread().getName()+":我正在学习");
//Thread.sleep(2000);
}catch (Exception e){
}finally {
lock.unlock();
}
}
}
结果:
下片介绍:读写锁。
原文链接:https://blog.csdn.net/qq_31142237/article/details/114648496
作者:zhqu4399
链接:http://www.javaheidong.com/blog/article/114357/4a05db1a350b2e3dc0bd/
来源:java黑洞网
任何形式的转载都请注明出处,如有侵权 一经发现 必将追究其法律责任
昵称:
评论内容:(最多支持255个字符)
---无人问津也好,技不如人也罢,你都要试着安静下来,去做自己该做的事,而不是让内心的烦躁、焦虑,坏掉你本来就不多的热情和定力
Copyright © 2018-2021 java黑洞网 All Rights Reserved 版权所有,并保留所有权利。京ICP备18063182号-2
投诉与举报,广告合作请联系vgs_info@163.com或QQ3083709327
免责声明:网站文章均由用户上传,仅供读者学习交流使用,禁止用做商业用途。若文章涉及色情,反动,侵权等违法信息,请向我们举报,一经核实我们会立即删除!