IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> 一 简单使用ReentrantLock -> 正文阅读

[Java知识库]一 简单使用ReentrantLock

ReentrantLock

在多线程中可以使用,Synchronized关键字实现线程与线程之间的同步互斥
但在JDK1.5中新增ReentrantLock类也能达到相同的目的, 并且扩展的功能也十分强大
比如 嗅探锁定/多路分支通知等功能, 而且在使用上也比Synchronized灵活很多

ReentrantLock 实现同步

public class ReentrantLockTest {

    static ReentrantLock reentrantLock = new ReentrantLock(); // 声明ReentrantLock

    public static void main(String[] args) {
        try {
            reentrantLock.lock(); // 加锁
            // ----
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            reentrantLock.unlock(); // 解锁
        }

    }
}

Condition 讲解

Synchronized 可以通过wait()/notify()/notifyAll() 实现 等待/通知模式, ReentrantLock 可以使用Condition类实现相同的功能, Condition 更加灵活, 比如实现多路通知功能 一个ReentrantLock对象可以创建多个Condition, 线程对象可以选择性的, 注册到不同的Condition上, 从而选择性的进行线程通知,

简单实现

condition.await() 方法必须在reentrantLock.lock() 方法内. 否则会提示异常信息

public class MyService {

    private ReentrantLock reentrantLock = new ReentrantLock();
    private Condition condition = reentrantLock.newCondition();
    private List<String> arrayList = new ArrayList<>();

    public void addItems() {
        try {
            reentrantLock.lock();
            if (arrayList.size() <= 0) {
                arrayList.add("新增一跳数据");
                System.out.println("addItems -- > 开始等待删除");
                condition.await();
            }
            System.out.println("addItems -- > 执行完了");
        } catch (Exception e) {

        } finally {
            reentrantLock.unlock();
        }
    }


    public void removeItems() {
        try {
            reentrantLock.lock();
            if (arrayList.size() >= 0) {
                arrayList.remove(0);
                System.out.println("removeItems -- > 元素已删除");
                condition.signal();
            }
            System.out.println("removeItems -- > 执行完了");
        } catch (Exception e) {

        } finally {
            reentrantLock.unlock();
        }
    }

}
  • 运行类
public class Run {

    public static void main(String[] args) throws InterruptedException {
        MyService myService = new MyService();
        new Thread(() -> {
            myService.addItems();
        }).start();
        Thread.sleep(1000);
        new Thread(() -> {
            myService.removeItems();
        }).start();
    }
}

唤醒指定线程

public class MyService {
    private ReentrantLock reentrantLock = new ReentrantLock();
    private Condition condition = reentrantLock.newCondition();
    private Condition conditionA = reentrantLock.newCondition();
    public void awaitA() {
        try {
            reentrantLock.lock();
            System.out.println("conditionA await 时间:" + System.currentTimeMillis());
            conditionA.await();
            System.out.println("conditionA 唤醒 时间:" + System.currentTimeMillis());
        } catch (Exception e) {

        } finally {
            reentrantLock.unlock();
        }
    }
    public void await() {
        try {
            reentrantLock.lock();
            System.out.println("condition await 时间:" + System.currentTimeMillis());
            condition.await();
            System.out.println("condition 唤醒 时间:" + System.currentTimeMillis());
        } catch (Exception e) {

        } finally {
            reentrantLock.unlock();
        }
    }
    public void signalA() {
        try {
            reentrantLock.lock();
            System.out.println("conditionA signal 时间:" + System.currentTimeMillis());
            conditionA.signal();
            System.out.println("conditionA signal 结束时间:" + System.currentTimeMillis());
        } catch (Exception e) {

        } finally {
            reentrantLock.unlock();
        }
    }
}
  • 运行类
public class Run {
    public static void main(String[] args) throws InterruptedException {
        MyService myService = new MyService();
        new Thread(() -> {
            myService.await();
        }).start();
        new Thread(() -> {
            myService.awaitA();
        }).start();
        Thread.sleep(1000);
        new Thread(() -> {
            myService.signalA();
        }).start();
    }
}

公平锁与非公平锁

ReentrantLock 分为 公平锁/非公平锁
公平锁表示: 线程获取锁的顺序是根据加锁的顺序, FIFO先进先出的原则
非公平锁表示: 获取锁是抢占机制, 是随机获得锁, 这个方式可能影响某些线程一直拿不到锁

  • 声明公平锁与非公平锁的方式
   // 默认非公平锁
    public ReentrantLock() {
        sync = new NonfairSync();
    }
    // 传递 true = 公平锁, false = 非公平锁
    public ReentrantLock(boolean fair) {
        sync = fair ? new FairSync() : new NonfairSync();
    }

公平锁

public class MyService {
    private ReentrantLock reentrantLock = new ReentrantLock(true);

    public void awaitA() {
        try {
            reentrantLock.lock();
            System.out.println(Thread.currentThread().getName() + "_ 获得锁");
        } catch (Exception e) {

        } finally {
            reentrantLock.unlock();
        }
    }
}
  • 运行类
public class Run {

    public static void main(String[] args) throws InterruptedException {
        MyService myService = new MyService();
        List<Thread> arr = new ArrayList<>();
        for (int i = 0; i < 11; i++) {
            Thread thread = new Thread(() -> {
                System.out.println(Thread.currentThread().getName()+"_ 运行了");
                myService.awaitA();
            }, i + "");
            arr.add(thread);
        }
        for (Thread thread : arr) {
            thread.start();
        }
    }
}
  • 输出结果
0_ 运行了
4_ 运行了
2_ 运行了
3_ 运行了
1_ 运行了
0_ 获得锁
4_ 获得锁
2_ 获得锁
3_ 获得锁
1_ 获得锁

可以看出来 根据线程被CPU调度的顺序, 也就是线程获得锁的顺序

非公平锁

只修改 初始化 ReentrantLock的方式

public class MyService {
    private ReentrantLock reentrantLock = new ReentrantLock(false);

    public void awaitA() {
        try {
            reentrantLock.lock();
            System.out.println(Thread.currentThread().getName() + "_ 获得锁");
        } catch (Exception e) {

        } finally {
            reentrantLock.unlock();
        }
    }
}

  • 输出结果
0_ 运行了
3_ 运行了
2_ 运行了
4_ 运行了
1_ 运行了
0_ 获得锁
3_ 获得锁
2_ 获得锁
4_ 获得锁
1_ 获得锁

顺序被打乱了

关键方法

hasQueuedThread(Thread thread)

查询指定线程是否正在等待获取此锁

HasQueuedThreads()

查询是否有线程正在等待获取此锁

hasWaiters()

查询是否有等待Condition的线程

hasQueueLength()

查询等待Condition的线程数量

isFair()

判断是否是公平锁

isHeldByCurrentThread()

查询当前线程是否是锁定状态

isLocked()

查询次锁定是否由任意线程保持

lockInterruptibly()

如果当前线程未被中断则获得锁定, 如果已被中断, 抛出异常

tryLock()

如果未被其他线程保持的情况下, 获得锁

tryLock(long timeout, TimeUnit unit)

在指定时间内没有被其他锁保持, 或者其他锁释放了锁, 则获取锁

Condition#awaitUninterruptibly

如果单独使用await() 方法然后调用中断会提示错误, 如果使用awaitUninterruptibly 则会正常向下执行

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2022-03-16 22:07:36  更:2022-03-16 22:11:33 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/24 8:29:57-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码