ReentrantLock和ReentrantReadWriteLock

2.5. ReentrantLock

2.5.1. ReentrantLock介绍

1)基本介绍
在Java多线程中,可以使用synchronized关键字实现线程之间的同步互斥,但是在JDK1.5中增加ReentrantLock类也可以达到同样的效果,并且在扩展功能上更加强大,比如有嗅探锁定、多路分支通知等,而且使用上比synchronized更加灵活。
2)样例程序

public class ReentrantBaseUsing {
    public static void main(String[] args) {
        Lock lock = new ReentrantLock();
        ReentrantBaseThread threadA = new ReentrantBaseThread(lock);
        threadA.setName("A");
        threadA.start();
        ReentrantBaseThread threadB = new ReentrantBaseThread(lock);
        threadB.setName("B");
        threadB.start();
    }
}

class ReentrantBaseThread extends Thread{
    private Lock lock ;

    public ReentrantBaseThread(Lock lock){
        this.lock = lock;
    }
    @Override
    public void run(){
        lock.lock();
        for (int i = 0; i < 2; i++) {
            try {
                System.out.println("线程"+Thread.currentThread().getName()+"打印"+i);
                Thread.sleep(1000);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        lock.unlock();
    }
}
2.5.2. ReentrantLock实现wait和notify

1)基本介绍
关键字synchronized与wait/notify方法相结合可以实现等待/通知模式,类ReentrantLock也可以利用Condition对象实现。Condition类可以实现多路通知功能,也就是在一个Lock对象中创建多个Condition实例,线程对象可以注册在指定的Condition中,从而有选择性的进行线程通知,在调试线程上更加灵活。
2)与synchronized的对比
Synchronized相当于整个Lock对象中只有一个单一Condition对象,所有的线程都是注册在它一个对象的身上,线程开始notifyAll时就需要通知所有正在等待的线程,被通知的线程是由JVM随机选择的,而且没有选择权,因此会出现效率低问题。但使用ReentrantLock结合Condition类可以实现有选择性的通知,是在Condition中默认提供的。
3)样例程序

public class WaitAndNotifyInReentrant {
    public static void main(String[] args) throws InterruptedException {
        WAndNInReentrantService service = new WAndNInReentrantService();
        WInReentrantThread waitThread = new WInReentrantThread(service);
        waitThread.start();

        Thread.sleep(1000);
        NInReentrantThread notifyThread = new NInReentrantThread(service);
        notifyThread.start();
    }
}

class WAndNInReentrantService{
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();

    public void await(){
        try{
            lock.lock();
            System.out.println("await方法开始....");
            condition.await();
            System.out.println("await方法结束");
            lock.unlock();
        }catch (InterruptedException e){
            e.printStackTrace();
        }
    }

    public void signal(){
        lock.lock();
        condition.signal();
        System.out.println("signal方法唤醒");
        lock.unlock();
    }
}

class WInReentrantThread extends Thread{
    private WAndNInReentrantService service;

    public WInReentrantThread(WAndNInReentrantService service){
        this.service = service;
    }

    @Override
    public void run(){
        this.service.await();
    }
}

class NInReentrantThread extends Thread{
    private WAndNInReentrantService service;

    public NInReentrantThread(WAndNInReentrantService service){
        this.service = service;
    }

    @Override
    public void run(){
        this.service.signal();
    }
}

4)注意事项
a.ReentrantLock类中使用await和signal方法需要在同步锁机制中才能使用。

2.5.3. 休眠线程分别唤醒

1)实现原理
通过多个condition对象实现不同线程的分别唤醒,也就是Condition对象可以唤醒部分指定的线程,这有助于提高程序的运行效率。
2)样例程序

public class MultiThreadNotify {
    public static void main(String[] args) throws InterruptedException {
        MultiThreadNotifyService service = new MultiThreadNotifyService();
        MultiAConditionIsNotifyThread ThreadA = new MultiAConditionIsNotifyThread(service);
        ThreadA.setName("A");
        ThreadA.start();

        MultiBConditionIsNotifyThread ThreadB = new MultiBConditionIsNotifyThread(service);
        ThreadB.setName("B");
        ThreadB.start();

        Thread.sleep(1000);
        service.signalAllA();
        service.signalAllB();
    }
}

class MultiThreadNotifyService{
    private Lock lock = new ReentrantLock();
    private Condition conditionA = lock.newCondition();
    private Condition conditionB = lock.newCondition();

    public void awaitA(){
        try{
            lock.lock();
            System.out.println("线程"+Thread.currentThread().getName()+"的await方法开始....");
            conditionA.await();
            System.out.println("线程"+Thread.currentThread().getName()+"的await方法结束");
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public void awaitB(){
        try{
            lock.lock();
            System.out.println("线程"+Thread.currentThread().getName()+"的await方法开始....");
            conditionB.await();
            System.out.println("线程"+Thread.currentThread().getName()+"的await方法结束");
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public void signalAllA(){
        lock.lock();
        conditionA.signal();
        System.out.println("所有关于ConditionA的线程全被signal方法唤醒");
        lock.unlock();
    }

    public void signalAllB(){
        lock.lock();
        conditionB.signal();
        System.out.println("所有关于ConditionB的线程全被signal方法唤醒");
        lock.unlock();
    }
}

class MultiAConditionIsNotifyThread extends Thread{
    private MultiThreadNotifyService service;

    public MultiAConditionIsNotifyThread(MultiThreadNotifyService service){
        this.service = service;
    }

    @Override
    public void run(){
        this.service.awaitA();
    }
}

class MultiBConditionIsNotifyThread extends Thread{
    private MultiThreadNotifyService service;

    public MultiBConditionIsNotifyThread(MultiThreadNotifyService service){
        this.service = service;
    }

    @Override
    public void run(){
        this.service.awaitB();
    }
}
2.5.4. Lock实现多消费者多生产者

1) 实现原理
基于ReentrantLock和Lock实现多生产者和多消费者。
2)样例程序

public class MultiPAndCInLock {
    public static void main(String[] args) {
        MultiPAndCInLockService service = new MultiPAndCInLockService();
        int size = 5;
        MultiPInLockThread[] multiPThread = new MultiPInLockThread[size];
        MultiCInLockThread[] multiCThread = new MultiCInLockThread[size];
        for (int i = 0; i < size; i++) {
            multiPThread[i] = new MultiPInLockThread(service);
            multiPThread[i].setName("A"+i);
            multiPThread[i].start();

            multiCThread[i] = new MultiCInLockThread(service);
            multiCThread[i].setName("B"+i);
            multiCThread[i].start();
        }
    }
}

class MultiPAndCInLockService{
    private Lock lock = new ReentrantLock();
    private Condition condition = lock.newCondition();
    private String data = "";

    public void productor(){
        try{
            lock.lock();
            while(!"".equals(data)){
                System.out.println("生产者"+Thread.currentThread().getName()+"中还有剩余数据未被消费");
                condition.await();
            }
            System.out.println("生产者"+Thread.currentThread().getName()+"开始生产数据");
            data = "data";
            condition.signalAll();
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

    public void consumer(){
        try{
            lock.lock();
            while("".equals(data)){
                System.out.println("消费者"+Thread.currentThread().getName()+"等待生产者制造数据");
                condition.await();
            }
            System.out.println("消费者"+Thread.currentThread().getName()+"开始消费数据");
            data = "";
            condition.signalAll();
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.unlock();
        }
    }

}

class MultiPInLockThread extends Thread{
    private MultiPAndCInLockService service;

    public MultiPInLockThread(MultiPAndCInLockService service){
        this.service = service;
    }

    @Override
    public void run(){
        this.service.productor();
    }
}

class MultiCInLockThread extends Thread{
    private MultiPAndCInLockService service;

    public MultiCInLockThread(MultiPAndCInLockService service){
        this.service = service;
    }

    @Override
    public void run(){
        this.service.consumer();
    }
}
2.5.5. 公平锁与非公平锁

1)基本介绍
Lock分为公平锁和非公平锁,公平锁:线程获取锁的顺序是按照加锁的顺序来分配的,先到先得;非公平锁:一种获取锁的抢占机制,是随机获取锁,可能造成有的线程一直得不到锁。
2)样例程序

public class FairLock {
    public static void main(String[] args) {
        FairLockService service = new FairLockService(true);
        int size = 5;
        FairThread[] threads = new FairThread[size];

        for (int i = 0; i < size; i++) {
            threads[i] = new FairThread(service);
        }
        for (int i = 0; i < size; i++) {
            threads[i].start();
        }
    }
}

class FairLockService{
    private Lock lock;

    public FairLockService(boolean IsFairLock){
        lock = new ReentrantLock(IsFairLock);
    }

    public void foo(){
        lock.lock();
        System.out.println("创建线程" + Thread.currentThread().getName());
        lock.unlock();
    }
}

class FairThread extends Thread{
    private FairLockService service;

    public FairThread(FairLockService service){
        this.service = service;
    }

    @Override
    public void run(){
        this.service.foo();
    }
}

2.6. ReentrantReadWriteLock

1)使用场景
ReentrantLock类具有完全互斥排他锁,也就是说同一时间内只有一个线程可以在运行ReentrantLock.lock方法后面的任务,这样虽然保证实例变量的线程安全性,但是效率十分低下。所以引入一种读写锁ReentrantReadWriteLock类,可以加快运行的效率,在某些不需要操作实例变量的方法中,完全可以使用读写锁来提升方法代码的运行效率。
2)使用介绍
读写锁具有两类锁,一是读操作(也称共享锁),二是写操作(也称排他锁)。换言之,多个读操锁之间不互斥,但是写锁与写锁之间、读锁与写锁之间会发生互斥。
3)样例程序

public class ReentrantReadAndWriteLock {
    public static void main(String[] args) throws InterruptedException {
        ReadWriteLockService service = new ReadWriteLockService();
        int size = 2;
        readLockThread[] readThread = new readLockThread[size];
        for (int i = 0; i < size; i++) {
            readThread[i] = new readLockThread(service);
            readThread[i].setName("读线程"+i);
            readThread[i].start();
        }

        Thread.sleep(3000);
        System.out.println("=========================================");

        WriteLockThread[] writeThread = new WriteLockThread[size];
        for (int i = 0; i < size; i++) {
            writeThread[i] = new WriteLockThread(service);
            writeThread[i].setName("写线程"+i);
            writeThread[i].start();
        }
    }
}


class ReadWriteLockService{
    private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();

    public void read(){
        try{
            lock.readLock().lock();
            System.out.println(Thread.currentThread().getName()+"开启读锁");
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getName()+"退出读锁");
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.readLock().unlock();
        }
    }

    public void write(){
        try{
            lock.writeLock().lock();
            System.out.println(Thread.currentThread().getName()+"开启写锁");
            Thread.sleep(2000);
            System.out.println(Thread.currentThread().getName()+"退出写锁");
        }catch (InterruptedException e){
            e.printStackTrace();
        }finally {
            lock.writeLock().unlock();
        }
    }
}

class readLockThread extends Thread{
    private ReadWriteLockService service;

    public readLockThread(ReadWriteLockService service){
        this.service = service;
    }

    @Override
    public void run(){
        this.service.read();
    }
}

class WriteLockThread extends Thread{
    private ReadWriteLockService service;

    public WriteLockThread(ReadWriteLockService service){
        this.service = service;
    }

    @Override
    public void run(){
        this.service.write();
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值