java多线程之Lock锁原理以及案例实现电影院卖票

简介: java多线程之Lock锁原理以及案例实现电影院卖票

为什么会出现Lock锁?

我们知道 synchronized 给代码加锁或解锁时,我们并没有直接看到在哪里加上了锁,在哪里释放了锁,为了更清晰的表达如何加锁和释放锁,JDK5以后提供了一个新的锁对象Lock

Lock锁使用

Lock实现提供比使用synchronized方法和语句可以获得更广泛的锁定操作

Lock中提供了获得锁和释放锁的方法:

  • void lock();//获得锁
  • void unlock();//释放锁
  • Lock类是接口,不能直接实例化,这里采用他的实现类ReentrantLock来实例化
    ReentrantLock的构造方法
    ReentrantLock():创建一个ReentrantLock的实例

代码实战

需求:某电影院目前正在上映国产大片,共有100张票,而它有3个窗口卖票,请设计一个程序模拟该电影院卖票

package com.heima.thread001;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class MyRun implements Runnable {
    int ticket = 0;
    Lock lock = new ReentrantLock();
    @Override
    public void run() {
        while (true){
            lock.lock();
            try {
                if (ticket == 100) {
                    break;
                }else {
                    ticket ++;
                    System.out.println(Thread.currentThread().getName() + "正在卖第" + ticket + "张票 ...");
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                lock.unlock();
            }
        }
    }
}
package com.heima.thread001;
import java.util.concurrent.ExecutionException;
public class TestDemo {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        MyRun myRun = new MyRun();
        //创建线程对象
        Thread t1 = new Thread(myRun);
        Thread t2 = new Thread(myRun);
        Thread t3 = new Thread(myRun);
        //起名字
        t1.setName("窗口1");
        t2.setName("窗口2");
        t3.setName("窗口3");
        //开启线程
        t1.start();
        t2.start();
        t3.start();
    }
}

运行结果如下:

窗口1正在卖第1张票 ...
窗口3正在卖第2张票 ...
窗口3正在卖第3张票 ...
窗口3正在卖第4张票 ...
窗口3正在卖第5张票 ...
窗口3正在卖第6张票 ...
窗口3正在卖第7张票 ...
窗口3正在卖第8张票 ...
窗口3正在卖第9张票 ...
窗口3正在卖第10张票 ...
窗口3正在卖第11张票 ...
窗口3正在卖第12张票 ...
窗口3正在卖第13张票 ...
窗口3正在卖第14张票 ...
窗口3正在卖第15张票 ...
窗口3正在卖第16张票 ...
窗口3正在卖第17张票 ...
窗口3正在卖第18张票 ...
窗口3正在卖第19张票 ...
窗口3正在卖第20张票 ...
窗口3正在卖第21张票 ...
窗口3正在卖第22张票 ...
窗口3正在卖第23张票 ...
窗口3正在卖第24张票 ...
窗口3正在卖第25张票 ...
窗口3正在卖第26张票 ...
窗口3正在卖第27张票 ...
窗口3正在卖第28张票 ...
窗口3正在卖第29张票 ...
窗口3正在卖第30张票 ...
窗口3正在卖第31张票 ...
窗口3正在卖第32张票 ...
窗口3正在卖第33张票 ...
窗口3正在卖第34张票 ...
窗口3正在卖第35张票 ...
窗口3正在卖第36张票 ...
窗口3正在卖第37张票 ...
窗口3正在卖第38张票 ...
窗口3正在卖第39张票 ...
窗口3正在卖第40张票 ...
窗口3正在卖第41张票 ...
窗口3正在卖第42张票 ...
窗口3正在卖第43张票 ...
窗口3正在卖第44张票 ...
窗口3正在卖第45张票 ...
窗口3正在卖第46张票 ...
窗口3正在卖第47张票 ...
窗口3正在卖第48张票 ...
窗口3正在卖第49张票 ...
窗口3正在卖第50张票 ...
窗口3正在卖第51张票 ...
窗口3正在卖第52张票 ...
窗口3正在卖第53张票 ...
窗口3正在卖第54张票 ...
窗口3正在卖第55张票 ...
窗口3正在卖第56张票 ...
窗口3正在卖第57张票 ...
窗口3正在卖第58张票 ...
窗口3正在卖第59张票 ...
窗口3正在卖第60张票 ...
窗口3正在卖第61张票 ...
窗口3正在卖第62张票 ...
窗口3正在卖第63张票 ...
窗口3正在卖第64张票 ...
窗口3正在卖第65张票 ...
窗口3正在卖第66张票 ...
窗口3正在卖第67张票 ...
窗口3正在卖第68张票 ...
窗口3正在卖第69张票 ...
窗口3正在卖第70张票 ...
窗口3正在卖第71张票 ...
窗口3正在卖第72张票 ...
窗口3正在卖第73张票 ...
窗口3正在卖第74张票 ...
窗口3正在卖第75张票 ...
窗口3正在卖第76张票 ...
窗口3正在卖第77张票 ...
窗口3正在卖第78张票 ...
窗口3正在卖第79张票 ...
窗口3正在卖第80张票 ...
窗口3正在卖第81张票 ...
窗口3正在卖第82张票 ...
窗口3正在卖第83张票 ...
窗口3正在卖第84张票 ...
窗口3正在卖第85张票 ...
窗口3正在卖第86张票 ...
窗口3正在卖第87张票 ...
窗口3正在卖第88张票 ...
窗口3正在卖第89张票 ...
窗口3正在卖第90张票 ...
窗口3正在卖第91张票 ...
窗口3正在卖第92张票 ...
窗口3正在卖第93张票 ...
窗口3正在卖第94张票 ...
窗口3正在卖第95张票 ...
窗口3正在卖第96张票 ...
窗口3正在卖第97张票 ...
窗口3正在卖第98张票 ...
窗口3正在卖第99张票 ...
窗口3正在卖第100张票 ...

知识扩展

1、synchronized和Lock的区别?

  • synchronized是关键字,Lock是接口。
  • synchronized无法获取锁的状态,Lock可以。
  • synchronized会自动释放锁,Lock需要手动。
  • synchronized没有Lock锁灵活(Lock锁可以自己定制)。

2、ReentrantLock 和 Synchronized 对比

  • ReentrantLock 通过 lock() 和 unlock() 加解锁,Synchronized会自动解锁,ReentrantLock需要手动解锁
  • ReentrantLock相比Synchronized的优势是: 可中断,公平锁,多个锁

3、Lock 接口的主要方法

  • void lock() — 如果lock是空闲的,当前线程就会获取到锁
  • boolean tryLock() — 如果lock可用,则获取锁并且返回true,否则返回false
  • void unlock() — 当前线程释放持有的锁
  • Condition newCondition() — 条件对象: 获取等待通知组件
  • getHoldCount() — 查询当前线程保持此锁的次数
  • getQueueLength() — 返回正在等待此锁的线程数量
  • getWaitQueueLength() — 返回正在等待与此锁相关给定条件的线程数量
  • hasWaiters(Condition condition) — 查询在特定Condition下是否有线程等待
  • hasQueuedThread(Thread thread) — 查询给定线程是否等待获取此锁
  • hasQueuedThreads — 是否有线程等待此锁
  • isFair() — 该锁是否是公平锁
  • isHeldByCurrentThread() — 当前线程是否保持锁定
  • isLock() — 此锁是否有任意线程占用
  • lockInterruptibly() — 如果当前线程未被中断,获取锁
  • tryLock() — 尝试获取锁,仅在调用时锁未被线程占用,获得锁
  • tryLock(long timeout, TimeUnit unit) — 如果锁在给定等待时间没有被另一个线程保持,获取锁

锁优化

  • 减少锁持有的时间 — 只在有线程安全要求的程序上加锁
  • 减少锁粒度 — 将大的对象拆成小对象,增加并行度,减少锁竞争
  • 锁分离 — 读写锁的思想,读的时候加read lock, 写的时候加 write lock
  • 锁粗化 — 保证线程持有锁的时间尽量短
  • 锁消除 — 如果发现不能被共享的对象,需要消除这些对象的锁操作


相关文章
|
10天前
|
存储 Java 数据库连接
java多线程之线程通信
java多线程之线程通信
|
1天前
|
安全 Java
java多线程(一)(火车售票)
java多线程(一)(火车售票)
|
1天前
|
Java 关系型数据库 MySQL
一套java+ spring boot与vue+ mysql技术开发的UWB高精度工厂人员定位全套系统源码有应用案例
UWB (ULTRA WIDE BAND, UWB) 技术是一种无线载波通讯技术,它不采用正弦载波,而是利用纳秒级的非正弦波窄脉冲传输数据,因此其所占的频谱范围很宽。一套UWB精确定位系统,最高定位精度可达10cm,具有高精度,高动态,高容量,低功耗的应用。
一套java+ spring boot与vue+ mysql技术开发的UWB高精度工厂人员定位全套系统源码有应用案例
|
1天前
|
安全 Java 程序员
Java中的多线程并发编程实践
【4月更文挑战第18天】在现代软件开发中,为了提高程序性能和响应速度,经常需要利用多线程技术来实现并发执行。本文将深入探讨Java语言中的多线程机制,包括线程的创建、启动、同步以及线程池的使用等关键技术点。我们将通过具体代码实例,分析多线程编程的优势与挑战,并提出一系列优化策略来确保多线程环境下的程序稳定性和性能。
|
2天前
|
Java 开发者
Java中多线程并发控制的实现与优化
【4月更文挑战第17天】 在现代软件开发中,多线程编程已成为提升应用性能和响应能力的关键手段。特别是在Java语言中,由于其平台无关性和强大的运行时环境,多线程技术的应用尤为广泛。本文将深入探讨Java多线程的并发控制机制,包括基本的同步方法、死锁问题以及高级并发工具如java.util.concurrent包的使用。通过分析多线程环境下的竞态条件、资源争夺和线程协调问题,我们提出了一系列实现和优化策略,旨在帮助开发者构建更加健壮、高效的多线程应用。
2 0
|
8天前
|
运维 NoSQL 算法
Java开发-深入理解Redis Cluster的工作原理
综上所述,Redis Cluster通过数据分片、节点发现、主从复制、数据迁移、故障检测和客户端路由等机制,实现了一个分布式的、高可用的Redis解决方案。它允许数据分布在多个节点上,提供了自动故障转移和读写分离的功能,适用于需要大规模、高性能、高可用性的应用场景。
15 0
|
10天前
|
存储 安全 Java
java多线程之原子操作类
java多线程之原子操作类
|
11天前
|
算法 JavaScript Java
Java多线程+分治求和,太牛了
`shigen`,一位擅长Java、Python、Vue和Shell的博主,分享编程知识和成长体验。在一次面试中因对高并发问题准备不足而受挫,随后深入学习,研究了线程池和经典案例——计算1亿数字的和。采用分治策略,`shigen`实现了Java版的归并排序,并对比了Python的简洁实现。通过多线程和分段求和优化,展示了如何高效解决大数求和问题,引入了分治思想的递归任务来进一步提升性能。未来将探讨`forkjoin`框架。关注`shigen`,每天学习新知识!
17 0
Java多线程+分治求和,太牛了
|
1月前
|
安全 Java
深入理解Java并发编程:线程安全与性能优化
【2月更文挑战第22天】在Java并发编程中,线程安全和性能优化是两个重要的主题。本文将深入探讨这两个主题,包括线程安全的基本概念,如何实现线程安全,以及如何在保证线程安全的同时进行性能优化。
15 0
|
17天前
|
安全 Java 容器
Java并发编程:实现高效、线程安全的多线程应用
综上所述,Java并发编程需要注意线程安全、可见性、性能等方面的问题。合理使用线程池、同步机制、并发容器等工具,可以实现高效且线程安全的多线程应用。
14 1

热门文章

最新文章