前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >7.Lock 同步锁

7.Lock 同步锁

作者头像
Devops海洋的渔夫
发布2022-03-23 16:22:24
2800
发布2022-03-23 16:22:24
举报
文章被收录于专栏:Devops专栏Devops专栏

7.Lock 同步锁

Lock( )

  • JDK 5.0开始,Java提供了更强大的线程同步机制——通过显式定义同步锁对象来实现同步。同步锁使用Lock对象充当。
  • java.util.concurrent.locks.Lock接口 是控制多个线程对共享资源进行访问的工具。锁提供了对共享资源的独占访问,每次只能有一个线程对 Lock 对象加锁,线程开始访问共享资源之前应先获得Lock对象。
  • ReentrantLock 类 是实现了 Lock 接口的一个实现类 ,它拥有与 synchronized 相同的并发性和内存语义,在实现线程安全的控制中,比较常用的是ReentrantLock类,可以显式加锁、释放锁。

显示锁 Lock

代码语言:javascript
复制
- 在 Java 5.0 之前,协调共享对象的访问时可以使用的机制只有 synchronized 和 volatile 。Java 5.0 后增加了一些新的机制,但并不是一种替代内置锁的方法,而是当内置锁不适用时,作为一种可选择的高级功能。

- ReentrantLock 实现了 Lock 接口,并提供了与 synchronized 相同的互斥性和内存可见性。但相较于 synchronized 提供了更高的处理锁的灵活性。

Lock(锁)示例

代码语言:javascript
复制
import java.util.concurrent.locks.ReentrantLock;

class A{
 private final ReentrantLock lock = new ReentrantLock(); // 创建锁
    
    public void m(){
        lock.lock();
        
        try{
         //保证线程安全的代码; }
        finally{
         lock.unlock(); 
        } 
    } 
}
// 注意:如果同步代码有异常,要将unlock()写入finally语句块

下面再写一个将前面账号取款的线程安全问题的示例。

线程安全问题的示例 - 多线程窗口卖票

1.首先创建一个售票的线程类
代码语言:javascript
复制
//创建线程类: 售卖车票
class Ticket implements Runnable {

    //成员属性
    private int tick = 100;

    //重写run
    @Override
    public void run() {
        //循环卖票,直到票卖完
        while (true) {
            //存在有票,继续售卖
            if (tick > 0) {
                //休眠500毫秒
                try {
                    Thread.sleep(200);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                //卖票
                tick--;
                //打印当前的票数
                System.out.println(Thread.currentThread().getName() + " 剩余票:" + tick);
            } else {
                break;
            }

        }
    }
}
2.创建三个线程,同时售票,演示线程安全问题
代码语言:javascript
复制
public class TestLock {
    public static void main(String[] args) {
        //创建线程类对象
        Ticket ticket = new Ticket();
        //创建三个线程
        new Thread(ticket, "1号窗口").start();
        new Thread(ticket, "2号窗口").start();
        new Thread(ticket, "3号窗口").start();
    }
}

测试执行如下:

image-20201102234826929

使用 Lock 解决线程安全问题

1.在售票的线程类创建 Lock,并且设置上锁以及释放锁

image-20201102235725467

代码语言:javascript
复制
//创建线程类: 售卖车票
class Ticket implements Runnable {
    //成员属性
    private int tick = 100;
    //创建 lock 锁
    private final ReentrantLock lock = new ReentrantLock();
    //重写run
    @Override
    public void run() {
        //循环卖票,直到票卖完
        while (true) {
            lock.lock(); // 上锁
            //存在有票,继续售卖
            try {
                if (tick > 0) {
                    //休眠500毫秒
                    try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    //卖票
                    tick--;
                    //打印当前的票数
                    System.out.println(Thread.currentThread().getName() + " 剩余票:" + tick);
                }
            } finally {
                lock.unlock(); // 在finally释放锁
            }

        }
    }
}
2.再次测试执行如下

image-20201102235505984

可以看到已经逐个执行了,没有出现重复值。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-02-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 海洋的渔夫 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 7.Lock 同步锁
    • Lock( 锁 )
      • 显示锁 Lock
      • Lock(锁)示例
      • 线程安全问题的示例 - 多线程窗口卖票
      • 使用 Lock 解决线程安全问题
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档