ReentrantLock的Condition选择性通知

2019-05-28  本文已影响0人  勇往直前z

今天浏览了并发同步的相关知识,使用ReentrantLock写了个小demo,主要关于选择性通知,在此记录一下。

1.介绍

ReentrantLock与synchronized 都是可重入锁、独占锁,ReentrantLock基于AQS,AQS基于CAS。

2.高级功能

①等待可中断
ReentrantLock提供了一种能够中断等待锁的线程的机制,通过lock.lockInterruptibly()来实现这个机制。也就是说正在等待的线程可以选择放弃等待,改为处理其他事情。
②可实现公平锁
即先到先得,通过构造函数ReentrantLock(boolean fair)制定。
③可实现选择性通知(锁可以绑定多个条件)
需要借助于Condition接口与newCondition() 方法,线程对象可以注册在指定的Condition中,从而可以有选择性的进行线程通知,在调度线程上更加灵活。

3.选择性通知实现

用简单的代码写了机器人给老板洗澡的过程。以下:
①机器人服务

package com.example.demo.practice;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class RobotService {

    private Lock lock = new ReentrantLock(true);
    public Condition washCondition = lock.newCondition();

    public void awaitCuoZao() {
        lock.lock();
        System.out.println("等着给老板搓澡...");
        System.out.println("开始等待时间:" + System.currentTimeMillis() + " -- 当前线程:" + Thread.currentThread().getName());
        try {
            washCondition.await();
            System.out.println("结束等待时间:" + System.currentTimeMillis() + " -- 当前线程:" + Thread.currentThread().getName());
            Thread.sleep(3000);
            System.out.println("搓澡完毕!");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void awaitMuyulu() {
        lock.lock();
        System.out.println("等着给老板打沐浴露...");
        System.out.println("开始等待时间:" + System.currentTimeMillis() + " -- 当前线程:" + Thread.currentThread().getName());
        try {
            washCondition.await();
            System.out.println("结束等待时间:" + System.currentTimeMillis() + " -- 当前线程:" + Thread.currentThread().getName());
            Thread.sleep(3000);
            System.out.println("打沐浴露完毕!");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void awaitChuanyi() {
        lock.lock();
        System.out.println("等着给老板更衣...");
        System.out.println("开始等待时间:" + System.currentTimeMillis() + " -- 当前线程:" + Thread.currentThread().getName());
        try {
            washCondition.await();
            System.out.println("结束等待时间:" + System.currentTimeMillis() + " -- 当前线程:" + Thread.currentThread().getName());
            Thread.sleep(3000);
            System.out.println("更衣完毕!");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void signalWash() {
        lock.lock();
        System.out.println("老板:给我洗澡");
        System.out.println("通知时间:" + System.currentTimeMillis() + " -- 当前线程:" + Thread.currentThread().getName());
        try {
            washCondition.signalAll();
        } finally {
            lock.unlock();
        }
    }

}

②线程类

package com.example.demo.practice;

public class WashThreadA implements Runnable {

    private RobotService robotService;

    public WashThreadA(RobotService robotService) {
        this.robotService = robotService;
    }

    @Override
    public void run() {
        robotService.awaitCuoZao();
    }

}

package com.example.demo.practice;

public class WashThreadB implements Runnable {

    private RobotService robotService;

    public WashThreadB(RobotService robotService) {
        this.robotService = robotService;
    }

    @Override
    public void run() {
        robotService.awaitMuyulu();
    }

}

package com.example.demo.practice;

public class WashThreadC implements Runnable {

    private RobotService robotService;

    public WashThreadC(RobotService robotService) {
        this.robotService = robotService;
    }

    @Override
    public void run() {
        robotService.awaitChuanyi();
    }

}

③测试类

package com.example.demo.practice;

import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

public class ReenTrantLockTest {

    public static void main(String[] args) throws InterruptedException {

        RobotService robotService = new RobotService();

        System.out.println("老板:我想洗澡,去准备一下。");

        WashThreadA washThreadA = new WashThreadA(robotService);
        Thread czReady = new Thread(washThreadA);
        czReady.setName("czReady");
        czReady.start();

        Thread.sleep(500);

        WashThreadB washThreadB = new WashThreadB(robotService);
        Thread myReady = new Thread(washThreadB);
        myReady.setName("myReady");
        myReady.start();

        Thread.sleep(500);

        WashThreadC washThreadC = new WashThreadC(robotService);
        Thread gyReady = new Thread(washThreadC);
        gyReady.setName("gyReady");
        gyReady.start();

        Thread.sleep(2000);

        robotService.signalWash();

    }
}

④控制台打印

老板:我想洗澡,去准备一下。
等着给老板搓澡...
开始等待时间:1559033214928 -- 当前线程:czReady
等着给老板打沐浴露...
开始等待时间:1559033215425 -- 当前线程:myReady
等着给老板更衣...
开始等待时间:1559033215926 -- 当前线程:gyReady
老板:给我洗澡
通知时间:1559033217926 -- 当前线程:main
结束等待时间:1559033217926 -- 当前线程:czReady
搓澡完毕!
结束等待时间:1559033220928 -- 当前线程:myReady
打沐浴露完毕!
结束等待时间:1559033223928 -- 当前线程:gyReady
更衣完毕!

代码地址:https://github.com/hardworkingman/take-a-bath

上一篇下一篇

猜你喜欢

热点阅读