Lock锁实现提供了比使用同步方法和语句可以获得的更广泛的锁操作。它们允许更灵活的结构,可能具有非常不同的属性,并且可能支持多个关联的条件对象。Lock提供了比synchronized更多的功能。实现比synchronized更细粒度的加锁操作
Lock与的Synchronized区别1Lock不是Java语言内置的,synchronized是Java语言的关键字,因此是内置特性。Lock是一个类,通过这个类可以实现同步访问;
2Lock和synchronized有一点非常大的不同,采用synchronized不需要用户去手动释放锁,当synchronized方法或者synchronized代码块执行完之后,系统会自动让线程释放对锁的占用;而Lock则必须要用户去手动释放锁,如果没有主动释放锁,就有可能导致出现死锁现象。
3 Lock可以让等待锁的线程响应中断interrupted(),而synchronized却不行,使用synchronized时,等待的线程会一直等待下去,不能够响应中断;.
4通过Lock可以知道有没有成功获取锁tryLock(),而synchronized却无法办到。
5 Lock可以提高多个线程进行读操作的效率。在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争) ,此时Lock的性能要远远优于synchronized.
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()
lock()方法是平常使用得最多的一个方法,就是用来获取锁。如果锁已被其他线程获取,则进行等待。
采用Lock,必须主动去释放锁,并且在发生异常时,不会自动释放锁。因此一般来说,使用Lock必须在try{}catch{}块中进行,并且将释放锁的操作放在finally块中进行,以保证锁一定被被释放,防止死锁的发生。
newCondition()关键字synchronized与wait()/notify()这两个方法一起使用可以实现等待/通知模式, Lock锁的newContition()方法返回Condition对象,Condition类也可以实现等待/通知模式。
用notify()通知时,JVM会随机唤醒某个等待的线程, 使用Condition类可以进行选择性通知, Condition比较常用的两个方法:
• await()会使当前线程等待,同时会释放锁,当其他线程调用signal()时,线程会重新获得锁并继续执行。
• signal()用于唤醒一个等待的线程。
注意:在调用Condition的await()/signal()方法前,也需要线程持有相关的Lock锁,调用await()后线程会释放这个锁,在singal()调用后会从当前Condition对象的等待队列中,唤醒 一个线程,唤醒的线程尝试获得锁, 一旦获得锁成功就继续执行。
ReentrantLock,意思是“可重入锁”,
ReentrantLock是唯一实现了Lock接口的类,并且ReentrantLock提供了更多的方法。
ReentrantLock可打断如果希望等待的状态可以被打断就可以使用lockInterruptibly()
如果是可中断模式,那么可以使用 interrupt 让等待中断
public void lockInterruptibly() throws InterruptedException {
this.sync.acquireInterruptibly(1);
}
package com.dongguo.sync;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author Dongguo
* @date 2021/9/12 0012-14:59
* @description:
*/
public class LockInterruptiblyDemo {
public static void main(String[] args) {
Lock lock = new ReentrantLock();
Thread t1 = new Thread(() -> {
try {
lock.lockInterruptibly();
} catch (InterruptedException e) {
e.printStackTrace();
System.out.println("等待锁的过程中被打断");
return;
}
try {
System.out.println(Thread.currentThread().getName()+"获得了锁");
} finally {
lock.unlock();
}
}, "t1");
lock.lock();
System.out.println(Thread.currentThread().getName()+"获得了锁");
t1.start();
try {
TimeUnit.SECONDS.sleep(1);
System.out.println(Thread.currentThread().getName()+"中断t1等待");
t1.interrupt();//中断等待
} catch (InterruptedException e) {
e.printStackTrace();
}finally {
lock.unlock();
}
}
}
运行结果
main获得了锁
main中断t1等待
等待锁的过程中被打断
java.lang.InterruptedException
at java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireInterruptibly(AbstractQueuedSynchronizer.java:898)
at java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireInterruptibly(AbstractQueuedSynchronizer.java:1222)
at java.util.concurrent.locks.ReentrantLock.lockInterruptibly(ReentrantLock.java:335)
at com.dongguo.sync.LockInterruptiblyDemo.lambda$main$0(LockInterruptiblyDemo.java:17)
at java.lang.Thread.run(Thread.java:748)
ReentrantLock锁超时
public boolean tryLock() {
return this.sync.nonfairTryAcquire(1);
}
public boolean tryLock(long var1, TimeUnit var3) throws InterruptedException {
return this.sync.tryAcquireNanos(1, var3.toNanos(var1));
}
立刻失败
package com.dongguo.sync;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author Dongguo
* @date 2021/9/12 0012-15:42
* @description:
*/
public class TimeOutLockDemo {
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
Thread t1 = new Thread(() -> {
if (!lock.tryLock()) {
System.out.println(Thread.currentThread().getName() + "获取不到立刻失败,返回");
return;
}
try {
System.out.println(Thread.currentThread().getName() + "获得了锁");
} finally {
lock.unlock();
}
}, "t1");
lock.lock();
System.out.println(Thread.currentThread().getName() + "获得了锁");
t1.start();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
运行结果
main获得了锁
t1获取不到立刻失败,返回
超时失败
package com.dongguo.sync;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author Dongguo
* @date 2021/9/12 0012-15:42
* @description:
*/
public class TimeOutLockDemo {
public static void main(String[] args) {
ReentrantLock lock = new ReentrantLock();
Thread t1 = new Thread(() -> {
try {
if (!lock.tryLock(1,TimeUnit.SECONDS)) {
System.out.println(Thread.currentThread().getName() + "获取不到等待1s后失败,返回");
return;
}
} catch (InterruptedException e) {
e.printStackTrace();
}
try {
System.out.println(Thread.currentThread().getName() + "获得了锁");
} finally {
lock.unlock();
}
}, "t1");
lock.lock();
System.out.println(Thread.currentThread().getName() + "获得了锁");
t1.start();
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
运行结果
main获得了锁
t1获取不到立刻失败,返回
ReentrantLock条件变量
synchronized 中也有条件变量,就是monitor的 waitSet 休息室,当条件不满足时进入 waitSet 等待 ReentrantLock 的条件变量比 synchronized 强大之处在于,它是支持多个条件变量的,这就好比 synchronized 是那些不满足条件的线程都在一间休息室等消息 而 ReentrantLock 支持多间休息室,比如有专门等烟的休息室、专门等早餐的休息室、唤醒时也是按休息室来唤 醒 使用要点: await 前需要获得锁 await 执行后,会释放锁,进入 conditionObject 等待 await 的线程被唤醒(或打断、或超时)取重新竞争 lock 锁 竞争 lock 锁成功后,从 await 后继续执行
实例:使用了线程间定制化通信的例子
A线程打印2次A,B线程打印3次B,C线程打印5次C,按照此顺序循环10轮
思路:创建三个线程给每个线程设置一个标志位
线程A判断flag=0,打印2次,修改flag=1,通知线程B
线程B判断flag=1,打印3次,修改flag=2,通知线程C
线程C判断flag=2,打印5次,修改flag=0,通知线程A
package com.dongguo.concurrent.lock;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @author Dongguo
* @date 2021/9/3 0003-15:01
* @description:
*/
public class ThreadOrderAccessDemo {
public static void main(String[] args) {
ShareResource shareResource = new ShareResource();
new Thread(() -> {
for (int i = 1; i {
for (int i = 1; i {
for (int i = 1; i
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?