ReentrantLock的使用

简介: ReentrantLock的使用

 (1)synchronized是独占锁,加锁和解锁的过程自动进行,易于操作,但不够灵活。ReentrantLock也是独占锁,加锁和解锁的过程需要手动进行,不易操作,但非常灵活。

(2)synchronized可重入,因为加锁和解锁自动进行,不必担心最后是否释放锁;ReentrantLock也可重入,但加锁和解锁需要手动进行,且次数需一样,否则其他线程无法获得锁。

(3)synchronized不可响应中断,一个线程获取不到锁就一直等着;ReentrantLock可以相应中断。

ReentrantLock公平锁,等待时间最长的线程先运行

首先做一个简易的售票功能

如下使用了reentrantlock公平锁,结果为

public class T1 {
    static int num = 23;
    static ReentrantLock lock = new ReentrantLock(true);
    public static void main(String[] args) {
        new Thread(T1::tt, "文化路").start();
        new Thread(T1::tt, "瑞达路").start();
        new Thread(T1::tt, "红旗路").start();
    }
    static void tt() {
        String na = Thread.currentThread().getName();
        while (num > 1) {
            lock.lock();
            num--;
            System.out.printf("%s:%d%n", na, num);
            if (num < 1) {
                break;
            }
            lock.unlock();
        }
    }
}

image.gif

image.gif

reentrantlock可以打断线程

例如一个线程睡眠时间太长,导致其他线程阻塞,则可以打断前一个进程。

public class T4 {
    static ReentrantLock lock = new ReentrantLock();
    public static void main(String[] args) {
        Thread a = new Thread(T4::add, "T1");
        a.start();
        a.interrupt();
        new Thread(() -> {
            try {
                TimeUnit.SECONDS.sleep(2);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            try {
                lock.lockInterruptibly();
                TimeUnit.SECONDS.sleep(1);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println("线程二");
            lock.unlock();
        }).start();
    }
    static void add() {
        try {
            lock.lock();
            TimeUnit.SECONDS.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        System.out.println("11");
        lock.unlock();
    }
}

image.gif

lockInterruptibly()获取锁,除非当前线程被中断。如果锁没有被其他线程持有,则获取锁并立即返回,将锁持有计数设置为1。如果当前线程已经持有这个锁,那么持有计数加1,该方法立即返回。如果锁被另一个线程持有,那么当前线程会因为线程调度的目的而被禁用,并处于休眠状态,直到发生以下两种情况之一:锁被当前线程获取;或其他线程中断当前线程。如果当前线程获得了锁,那么锁保持计数被设置为1如果当前线程:在进入此方法时设置其中断状态;或在获取锁时被中断然后,InterruptedException被抛出,当前线程的interruptec状态被清除。在此实现中,由于此方法是显式的中断点,因此优先于响应中断,而不是正常或可重入获取锁。

目录
相关文章
|
11月前
|
存储 关系型数据库 MySQL
什么是联合索引
【10月更文挑战第15天】什么是联合索引
740 4
|
10月前
|
SQL 数据库 开发者
达梦数据库 【-6111: 字符串转换出错】问题处理
在更新数据库某个值属性时,遇到了“字符串转换出错”的错误。经过分析,发现是由于 `id` 字段实际上是字符串类型而非数值类型导致的。最终通过将 `id` 的值改为字符串类型解决了问题。此问题提醒我们在处理数据库时要仔细检查表结构,不要凭经验臆断字段类型。
|
9月前
|
存储 Oracle 关系型数据库
数据库传奇:MySQL创世之父的两千金My、Maria
《数据库传奇:MySQL创世之父的两千金My、Maria》介绍了MySQL的发展历程及其分支MariaDB。MySQL由Michael Widenius等人于1994年创建,现归Oracle所有,广泛应用于阿里巴巴、腾讯等企业。2009年,Widenius因担心Oracle收购影响MySQL的开源性,创建了MariaDB,提供额外功能和改进。维基百科、Google等已逐步替换为MariaDB,以确保更好的性能和社区支持。掌握MariaDB作为备用方案,对未来发展至关重要。
226 3
|
9月前
|
Java Maven
java项目中jar启动执行日志报错:no main manifest attribute, in /www/wwwroot/snow-server/z-server.jar-jar打包的大小明显小于正常大小如何解决
在Java项目中,启动jar包时遇到“no main manifest attribute”错误,且打包大小明显偏小。常见原因包括:1) Maven配置中跳过主程序打包;2) 缺少Manifest文件或Main-Class属性。解决方案如下:
2189 8
java项目中jar启动执行日志报错:no main manifest attribute, in /www/wwwroot/snow-server/z-server.jar-jar打包的大小明显小于正常大小如何解决
|
存储 监控 数据库
neo4j如何查看日志信息
【5月更文挑战第2天】neo4j如何查看日志信息
732 2
|
安全
[AIGC] 如何建立和优化你的工作流?
[AIGC] 如何建立和优化你的工作流?
337 1
|
存储 缓存 监控
JVM详解 --- 垃圾回收机制
JVM详解 --- 垃圾回收机制
JVM详解 --- 垃圾回收机制
|
Java API 开发者
Bladex生成Swagger的方法
Bladex生成Swagger的方法
|
存储 Python
如何在代理的IP被封后立刻换下一个IP继续任务
如何在代理的IP被封后立刻换下一个IP继续任务
140 5