Lock接口——JUC随记2

文章介绍了Java中synchronized的三种使用方式及字节码实现,强调了其在多线程编程中的应用。然后对比了Lock接口,指出Lock提供了更灵活的锁操作和更详细的控制,但也需要程序员手动管理锁的释放,以避免死锁。通过示例展示了如何使用ReentrantLock实现售票场景的线程安全。
摘要由CSDN通过智能技术生成

1、synchronized

1.1、synchronized的三种应用方式

一. 修饰实例方法,作用于当前实例加锁,进入同步代码前要获得当前实例的锁。
二. 修饰静态方法,作用于当前类对象加锁,进入同步代码前要获得当前类对象的锁。
三. 修饰代码块,指定加锁对象,对给定对象加锁,进入同步代码库前要获得给定对象。

1.2、synchronized的字节码指令

synchronized同步块使用了monitorenter和monitorexit指令实现同步,这两个指令,本质上都是对一个对象的监视器(monitor)进行获取,这个过程是排他的,也就是说同一时刻只能有一个线程获取到由synchronized所保护对象的监视器。
  线程执行到monitorenter指令时,会尝试获取对象所对应的monitor所有权,也就是尝试获取对象的锁,而执行monitorexit,就是释放monitor的所有权。

1.3多线程编程的简单实现

第一步:创建一个资源类
第二步:创建多个线程,调用资源类的方法
例如:

public class SaleTicket {
    public static void main(String[] args) {
        //第二步:创建多个线程,调用资源类的方法
        Ticket ticket = new Ticket();
        new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i=0;i<40;i++){
                    ticket.sale();
                }
            }
        },"ThreadA").start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i=0;i<40;i++){
                    ticket.sale();
                }
            }
        },"ThreadB").start();
        new Thread(new Runnable() {
            @Override
            public void run() {
                for(int i=0;i<40;i++){
                    ticket.sale();
                }
            }
        },"ThreadC").start();
    }
}
//第一步:创建一个资源类
class  Ticket{
    private int number=30;
    public synchronized void sale(){
        if(number>0){
            System.out.println(Thread.currentThread().getName()+":卖出第"+number--+"张票,剩下"+number+"张票");
        }
    }
}

运行结果:
在这里插入图片描述

2、Lock接口

2.1、定义

Lock锁实现提供了比使用同步方法和语句可以获得的更广泛的锁操作。它们允许更灵活的结构,可能具有非常不同的属性,并且可能支持多个关联的条件对
象。Lock提供了比synchronized更多的功能。

2.2、Lock与Synchronized的区别

  1. Lock 是-个接口,而synchronized是Java中的关键字, synchronized是内
    置的语言实现;
  2. synchronized 在发生异常时,会自动释放线程占有的锁,因此不会导致死锁现象发生;而Lock在发生异常时,如果没有主动通过unLock0去释放锁,则很可能造成死锁现象,因此使用Lock时需要在finally块中释放锁;
  3. Lock 可以让等待锁的线程响应中断,而synchronized却不行,使用
    synchronized时,等待的线程会一直等待 下去,不能够响应中断;
  4. 通过Lock可以知道有没有成功获取锁,而synchronized却无法办到。
  5. Lock 可以提高多个线程进行读操作的效率。在性能上来说,如果竞争资源不激烈,两者的性能是差不多的,而当竞争资源非常激烈时(即有大量线程同时竞争) , 此时Lock的性能要远远优于synchronized。

2.3、示例

import java.util.concurrent.locks.ReentrantLock;

//创建多个线程调用资源类的方法
public class LockSaleTicket {
    public static void main(String[] args) {
        LTicket lTicket = new LTicket();
        new Thread(()->{
            lTicket.sale();
        },"线程A").start();
        new Thread(()->{
            for (int i = 0; i <30 ; i++) {
                lTicket.sale();
            }
        },"线程B").start();
        new Thread(()->{
            lTicket.sale();
        },"线程C").start();
    }
}
//第一步:创建一个资源类
class LTicket{
    int number=30;
    private final ReentrantLock lock =new ReentrantLock();
    public void sale(){
         //上锁
         lock.lock();
         try{
             //判断是否有票
             if(number>0){
                 System.out.println(Thread.currentThread().getName()+":卖出第"+number--+"张票,剩下"+number+"张票");
             }
         }finally {
             //解锁
             lock.unlock();
         }
    }
}

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值