ReetrantLock(选择性通知与公平锁) 侃一侃西游记之--太上老君炼丹的故事

本文通过西游记中太上老君炼丹的故事,阐述了ReentrantLock的选择性通知和公平锁概念。文章详细比较了ReentrantLock与synchronized的差异,包括等待可中断、公平锁实现以及选择性通知,并通过代码示例进行解释。

一.写在开头

二.太上老君炼丹的故事

三.ReetrantLock选择性通知与公平锁,及部分特性与synchronized的比较

四.代码


一.写在开头

通过一个西游记里头经典的桥段,太上老君炼丹,初步介绍ReetrantLock的选择性通知,ReetrantLock公平锁/非公平锁。希望能够帮助到点进来的你。配合跑代码看结果效果更佳。

二.太上老君炼丹的故事

书接上回,太上老君者,大道之主宰...(此处省略一万字)...玉皇大帝祭出了斩妖刀,也无法将老孙灭杀。太上老君站了出来,请玉帝将老孙交付于他,只要他将老孙放进炼丹炉用三昧真火烧炼,即可灭杀老孙。此时,太上老君带着他的三个徒弟来到了炼丹洞府:都率宫!

(正片开始!)太上老君有三个徒弟A,B,C,辅助他炼化妖猴。

 徒弟A徒弟B徒弟C
职责负责开炉负责把悟空扔进炼丹炉负责封炉

 

炼化流程:徒弟们先各自准备,准备好后,太上老君一声令下。徒弟A开炉-->徒弟B把悟空扔进炼丹炉-->徒弟C封炉,分工明确 

Demo中,太上老君为test主线程,启动三个徒弟线程ABC,线程A B C先等待,等主线程signalAll()唤醒所有等待线程。

运行截图:

三.ReetrantLock选择性通知与公平锁,及部分特性与synchronized的比较

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

ReetrantLock的特性:

1.等待可中断
ReentrantLock提供了一种能够中断等待锁的线程的机制,通过lock.lockInterruptibly()来实现这个机制。也就是说正在等待的线程可以选择放弃等待,改为处理其他事情。

相比synchronized,synchronized不可中断。
2.可实现公平锁

注意,new ReentrantLock()默认情况下,使用非公平锁。本例采用了公平锁new ReentrantLock(true),保证线程获取锁的顺序。

简述一下公平锁和非公平锁:

公平锁:先进来的线程先执行。

非公平锁:后进来的线程也可能先执行。

相比synchronized,synchronized只能是非公平锁。
3.可实现选择性通知(锁可以绑定多个条件)
需要借助于Condition接口与newCondition() 方法,线程对象可以注册在指定的Condition中,从而可以有选择性的进行线程通知,在调度线程上更加灵活。

四.例子代码

package ReetrantLockTest;

public class ReenTrantLockTest {

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

        OrderService orderService = new OrderService();

        System.err.println("太上老君:今日老夫终于擒获此妖猴!为天庭除害!徒儿们现在去准备开炉事宜,让老夫炼了这厮!");
        
        PupilThreadA pupilThreadA = new PupilThreadA(orderService);
        Thread pupilA = new Thread(pupilThreadA);
        pupilA.setName("徒弟A(负责开炉)");
        pupilA.start();

        Thread.sleep(500);
        
        PupilThreadB pupilThreadB = new PupilThreadB(orderService);
        Thread pupilB = new Thread(pupilThreadB);
        pupilB.setName("徒弟B(负责把悟空扔进炼丹炉)");
        pupilB.start();

        Thread.sleep(500);

        PupilThreadC pupilThreadC = new PupilThreadC(orderService);
        Thread pupilC = new Thread(pupilThreadC);
        pupilC.setName("徒弟C(持有太上老君的法器)");
        pupilC.start();

        Thread.sleep(2000);

        orderService.signalAll();
        Thread.sleep(500);
        System.err.println("太上老君:干的漂亮!!");
    }
}

 

package ReetrantLockTest;

public class PupilThreadA implements Runnable {

    private OrderService orderService;

    public PupilThreadA(OrderService robotService) {
        this.orderService = robotService;
    }

    @Override
    public void run() {
    	orderService.awaitOpen();
    }

}

 

package ReetrantLockTest;

public class PupilThreadB implements Runnable {

    private OrderService orderService;

    public PupilThreadB(OrderService robotService) {
        this.orderService = robotService;
    }

    @Override
    public void run() {
    	orderService.awaitThrow();
    }

}

 

package ReetrantLockTest;

public class PupilThreadC implements Runnable {

    private OrderService orderService;

    public PupilThreadC(OrderService robotService) {
        this.orderService = robotService;
    }

    @Override
    public void run() {
    	orderService.awaitWeapon();
    }

}

 

package ReetrantLockTest;

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

public class OrderService {

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

    public void awaitOpen() {
        lock.lock();
        System.out.println("");
        System.out.println("----当前线程:" + Thread.currentThread().getName());
        System.out.println("徒弟A开始画解封炼丹炉的符咒...");
        System.out.println("徒弟A画完了符咒-开始等待老君下命令(await()开始等待)");
        System.out.println("");
        try {
        	orderCondition.await();
        	System.out.println("----当前线程:" + Thread.currentThread().getName());
            System.out.println("徒弟A接到老君命令-结束等待-开始用符咒解封炼丹炉");           
            System.out.println("炼丹炉解封完毕!");
            System.out.println("");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void awaitThrow() {
        lock.lock();
        System.out.println("----当前线程:" + Thread.currentThread().getName());
        System.out.println("徒弟B开始做广播体操热身...");
        System.out.println("徒弟B热身完毕-开始等待老君下命令(await()开始等待) ");
        System.out.println("");
        try {
        	orderCondition.await();
        	System.out.println("----当前线程:" + Thread.currentThread().getName());
            System.out.println("徒弟B接到老君命令-结束等待-用天生神力把悟空扔进炼丹炉 ");            
            System.out.println("妖猴入炉完毕!");
            System.out.println("");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void awaitWeapon() {
        lock.lock();
        System.out.println("----当前线程:" + Thread.currentThread().getName());
        System.out.println("徒弟C开始屁颠屁颠跑去拿太上老君的法器...");
        System.out.println("徒弟C准备好了法器-开始等待老君下命令(await()开始等待) ");
        try {
        	orderCondition.await();
        	System.out.println("----当前线程:" + Thread.currentThread().getName());
            System.out.println("徒弟C-结束等待-开始用老君法器封印炼丹炉"); 
            System.out.println("封炉完毕!");
            System.out.println("");
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void signalAll() {
        lock.lock();
        System.out.println("");
        System.out.println("----当前线程:" + Thread.currentThread().getName());
        System.err.println("太上老君:徒儿们,都准备好了吧?!干活!!!(signalAll()唤醒所有的等待线程)");
        System.out.println("");
        try {
        	
        	orderCondition.signalAll();
        } finally {
            lock.unlock();
        }
    }

}

都看到这里了,点个赞再走呗~你有酒吗?我有故事。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值