欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

Java多线程 - ReentrantLock实际开发中的应用场景

程序员文章站 2022-07-12 11:30:23
...

1. 公平锁,线程排序执行,防饿死应用场景

公平锁原则必须按照锁申请时间上先到先得的原则分配机制场景;

1).实现逻辑 上(包括:软件中函数计算、业务先后流程;硬件中操作实现中顺序逻辑)的顺序排队机制的场景;
软件场景:用户交互View中对用户输入结果分析类,分析过程后面算法依赖上一步结果的场景,例如:推荐算法实现[根据性别、年龄筛选]、阻塞队列的实现;

硬件场景:需要先分析确认用户操作类型硬件版本或者厂家,然后发出操作指令;例如:自动售货机;

2).现实 生活中 时间排序的 公平原则:

例如:客服分配,必须是先到先服务,不能出现饿死现象;公平锁实现见上文:

公平锁与非公平锁的测试demo:逻辑代码实现那就没法子实现了;

阻塞队列的实现就是时间上的公平原则。

2. 非公平锁,效率的体现者

实际开发中最常用的的场景就是非公平锁,ReentrantLock无参构造默认就时候非公平锁;适应场景除了上面公平锁中提到的其他都是非公平锁的使用场景;

3. ReentrantLock.Condition线程通信

ReentrantLock.Condition线程通信是最长见的面试题,这里以最简单例子:两个线程之间交替打印 26英文字母和阿拉伯数字为demo:

private void alternateTask() {
        ReentrantLock lock = new ReentrantLock();
        Condition condition1 = lock.newCondition();
        Condition condition2 = lock.newCondition();
        Thread thread1 = new Thread(() -> {
            try {
                lock.lock();
                for (int i = 65; i < 91; i++) {
                    System.out.println("----------thread1------- " + (char) i);
                    condition2.signal();
                    condition1.await();
                }
                condition2.signal();
            } catch (Exception e) {
            } finally {
                lock.unlock();
            }
        });
        Thread thread2 = new Thread(() -> {
            try {
                lock.lock();
                for (int i = 0; i < 26; i++) {
                    System.out.println("----------thread2------- " + i);
                    condition1.signal();
                    condition2.await();
                }
                condition1.signal();
            } catch (Exception e) {
            } finally {
                lock.unlock();
            }
        });
        thread1.start();
        thread2.start();
    }

4.同步功能的使用

实现线程同步锁synchronized 功能【单例为例】

  private Singleton() {
    }

    private static Singleton instance;
    private static Lock lock = new ReentrantLock();

    public static Singleton getInstance() {
        lock.lock();
        try {
            if (instance == null) {
                instance = new Singleton();
            }
        } finally {
            lock.unlock();
        }
        return instance;
    }

5. 中断杀器应用

ReentrantLock中lockInterruptibly()和lock()最大的区别就是中断相应问题:

lock()是支持中断相应的阻塞试的获取方式,因此即使主动中断了锁的持有者,但是它不能立即unlock(),仍然要机械版执行完所有操作才会释放锁。

lockInterruptibly()是 优先响应中断的,这样有个优势就是可以通过tryLock()、tryLock(timeout, TimeUnit.SECONDS)方法,中断优先级低的Task,及时释放资源给优先级更高的Task,甚至看到网上有人说可以做防止死锁的优化;
 

 ReentrantLock lock = new ReentrantLock();
        try {
            lock.lockInterruptibly();
            if (lock.tryLock(timeout, TimeUnit.SECONDS)) {
                //TODO
            }else{
                //超时直接中断优先级低的Task
                Thread.currentThread().interrupt();
                lock.lock();
                //TODO
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
           

6. 非重要任务Lock使用

优先级较低的操作让步给优先级更高的操作,提示代码效率/用户体验;忽略重复触发

1).用在定时任务时,如果任务执行时间可能超过下次计划执行时间,确保该有状态任务只有一个正在执行,忽略重复触发。

2).用在界面交互时点击执行较长时间请求操作时,防止多次点击导致后台重复执行(忽略重复触发)。

以上两种情况多用于进行非重要任务防止重复执行,(如:清除无用临时文件,检查某些资源的可用性,数据备份操作等)

tryLock()功能:如果已经获得锁立即返回fale,起到防止重复而忽略的效果 

ReentrantLock lock = new ReentrantLock();
      //防止重复执行,执行耗时操作,例如用户重复点击
       if (lock.tryLock()) {
           try {
			//TO DO
           } finally {
             lock.unlock();
           }
       }
      

超时放弃

定时操作的例如:错误日志、定时过期缓存清理的操作,遇到优先级更高的操作占用资源时,暂时放弃本次操作下次再处理,可以起到让出CPU,提升用户体验;

  ReentrantLock lock = new ReentrantLock();
        try {
            if (lock.tryLock(timeout, TimeUnit.SECONDS)) {
                //TO DO
            }
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }