2. Lock (锁的)接口
一、 复习synchronized
他是Java的关键字,是一种同步锁,能够修饰 一个 对象,变量,方法,
来控制这个所修饰的,被顺序的访问,
1.1 多线程的编程步骤:
第一:创建一个资源类,属性和操作方法
第二:创建多线程,调用类里面的操作方法
结合synchronized 锁 和 多线程的编程步骤实现卖票的功能 :(高内聚低耦合)
public class SaleTicket {
//第二步,创建多个线程,调用资源类的操作方法
public static void main(String[] args) {
Ticket ticket = new Ticket();
//具体创建线程的方法是new Thread(new Runnable({ 重写run方法},线程名)
Thread t1 = new Thread(() -> {
for(int i =0; i<10;i++){
ticket.sale();
}
},"t1"
);
t1.start();
Thread t2= new Thread(
//Lambda 表达式
() ->{ for (int i = 0; i < 10; i++) {
ticket.sale();
} } ,"t2"
);
t2.start();
}
}
//多线程实现卖票的功能 synchronized方式
class Ticket{ //第一步 资源类 票
private int num =30; //定义票的数量
public synchronized void sale(){ //synchronized
//给这个资源加上锁,防止多线程的错误
//资源的操作 卖票的方法
if(num>0){
System.out.println(Thread.currentThread().getName()+
" 卖出了: 1张 还剩下"+(num--)); }
}
}
代码执行的时候,t1 和 t2两个线程执行堆叠在一起,这是因为不同线程不同对象启动执行,都可以访问
二、 Lock接口
为锁和等待条件提供一个框架的接口和类,不同于内置同步和监视器, LOCK是类,可通过类实现同步访问,多个接口实现类:可重入锁等
lock的编程步骤同synchronized
可重入锁的代码定义private final ReentrantLock lock = new ReentrantLock(true);
上锁lock.lock();
解锁lock.unlock();
上锁与解锁中的代码如果出现异常,解锁会执行不了,所以最好加try..finally
import java.util.concurrent.locks.ReentrantLock;
public class LSaleTicket {
//第二步 创建多个线程,调用资源类的操作方法
//创建三个线程
public static void main(String[] args) {
LTicket ticket = new LTicket();
new Thread(()-> {
for (int i = 0; i < 40; i++) {
ticket.sale();
}
},"AA").start();
new Thread(()-> {
for (int i = 0; i < 40; i++) {
ticket.sale();
}
},"BB").start();
new Thread(()-> {
for (int i = 0; i < 40; i++) {
ticket.sale();
}
},"CC").start();
}
}
class LTicket {
private int num = 30; //票数量
private final ReentrantLock lock = new ReentrantLock(true); //创建可重入锁
public void sale() { //卖票方法
//上锁
lock.lock();
try {
if(num > 0) { //判断是否有票
System.out.println(Thread.currentThread().getName()+" :卖出 1张 剩余:"+(num--));
}
} finally {
//解锁
lock.unlock();
}
}
}
2.1 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()
方法用来获取锁
-
如果锁已被其他线程获取,则进行等待
-
发生异常不会自动解锁,需用在 try{}catch{}块中进行
lock.lock();
try{
//处理任务
}catch(Exception ex){
}finally{
lock.unlock(); //释放锁
}
Condition 类也可以实现等待/通知模式
关键字 synchronized 与 wait()/notify()这两个方法一起使用可以实现等待/通知模式,Lock 锁的 newContition()方法返回 Condition 对象,Condition 类也可以实现等待/通知模式
用 notify()通知时,JVM 会随机唤醒某个等待的线程, 使用 Condition 类可以进行选择性通知, Condition 比较常用的两个方法:
1. await()会使当前线程等待,同时会释放锁,当其他线程调用 signal()时,线程会重新获得锁并继续执行
2. signal()用于唤醒一个等待的线程ReentrantLock 是唯一实现了 Lock 接口的类,并且 ReentrantLock 提供了更多的方法
ReentrantLock可重入锁Reentrant ReadWriteLock 里面提供了很多丰富的方法,不过最主要的有两个方法:readLock()和 writeLock()用来获取读锁和写锁
writeLock();来获取读锁
readLock();获取写锁
public interface ReadWriteLock {
Lock readLock();
Lock writeLock();
}
2.2 两者差异
synchronized与lock的异同:1. synchronized是java关键字,内置,而lock不是内置,是一个类,可以实现同步访问
且 比 synchronized中的方法更加丰富
2.synchronized不会手动释放锁,而lock需手动释放锁(不解锁会出现死锁,需要在 finally 块中释放锁)
3. lock等待锁的线程会相应中断,而synchronized不会相应,只会一直等待
4. 通过 Lock 可以知道有没有成功获取锁,而 synchronized 却无法办到
5. Lock 可以提高多个线程进行读操作的效率(当多个线程竞争的时候)
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· DeepSeek 开源周回顾「GitHub 热点速览」
· 物流快递公司核心技术能力-地址解析分单基础技术分享
· .NET 10首个预览版发布:重大改进与新特性概览!
· AI与.NET技术实操系列(二):开始使用ML.NET
· 单线程的Redis速度为什么快?