Java多线程编程-ReentrantLock(1)

Java多线程编程-ReentrantLock使用及其源码解析


在java多线程开发中,我们可以使用 synchronized关键字来实现线程之间的同步互斥,我们也可以使用 ReentrantLock实现更多的功能,如嗅探锁定。多路分支通知等功能,使用上会比synchronized更加灵活。

ReentrantLock简单使用

可重入的互斥Lock,具有与使用sync方法和语句访问的隐式监视器锁相同的基本行为和语义。
由上一次成功锁定但尚未解锁的线程所有。当该锁不属于另一个线程时,调用lock的线程将返回,并成功获取该锁。如果当前线程已经拥有该锁,则该方法将立即返回。可以使用方法 isHeldByCurrentThread和getHoldCount进行检查。

public class ReentrantLockV1Main {
    public static ReentrantLock reentrantLock = new ReentrantLock();
    public static void main(String[] args) {
        Thread thread01 = new Thread(() -> {
            reentrantLock.lock();
            try {
                for (int i = 0; i < 5; i++) {
                    System.out.println("current thread name :" + Thread.currentThread().getName() + " value:" + (i + 1));
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                reentrantLock.unlock();
            }
        }, "thread01");

        Thread thread02 = new Thread(() -> {
            reentrantLock.lock();
            try {
                for (int i = 0; i < 5; i++) {
                    System.out.println("current thread name :" + Thread.currentThread().getName() + " value:" + (i + 1));
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                reentrantLock.unlock();
            }
        }, "thread02");

        Thread thread03 = new Thread(() -> {
            reentrantLock.lock();
            try {
                for (int i = 0; i < 5; i++) {
                    System.out.println("current thread name :" + Thread.currentThread().getName() + " value:" + (i + 1));
                }
            } catch (Exception e) {
                e.printStackTrace();
            } finally {
                reentrantLock.unlock();
            }
        }, "thread03");
        thread01.start();
        thread02.start();
        thread03.start();
    }
}

运行结果:
在这里插入图片描述
使用lock方法获取锁,使用unlock方法释放锁。每个线程同步执行。

ReentrantLock实现等待通知

我们知道synchronized和wait/notify可以实现等待通知模式,ReentrantLock也可以实现,但是要借助Condition对象。在一个lock对象里面可以创建多个condition实例,线程对象可以注册在指定的condition中,从而可以有选择性的进行线程的通知。在调度线程上更加灵活。
在没有获得锁的情况下,进行wait操作会报错:

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

    public void waitFun() {
        try {
            condition.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}

线程类:

public class ReentranLockObj1T1 extends Thread {

    private ReentranLockObj1 reentranLockObj1;

    public ReentranLockObj1T1(ReentranLockObj1 reentranLockObj1) {
        this.reentranLockObj1 = reentranLockObj1;
    }

    @Override
    public void run() {
        reentranLockObj1.waitFun();
    }
}

运行结果:
![在这里插入图片描述](https://img-blog.csdnimg.cn/20210404105032778.png?x-oss-process=image/watermark,type_ZmFuZ3poZW5naGVpdGk,shadow_10,text_aHR0cHM6Ly9ibG9nLmNzZG4ubmV0L3FpYW4xMzE0NTIwaHU=,size_16,color_FFFFFF,t_70

我们看看该类的Condition接口源码:

public interface Condition {
//使当前线程等待,直到发出信号或被中断
void await() throws InterruptedException;
//使当前线程等待,直到发出信号
void awaitUninterruptibly();
//使当前线程等待,直到发出信号或被中断或经过指定的等待时间为止
long awaitNanos(long nanosTimeout) throws InterruptedException;
//使当前线程等待,直到发出信号或被中断,或者经过指定的等待时间
boolean await(long time, TimeUnit unit) throws InterruptedException;
//使当前线程等待,直到发出信号或被中断,或者经过指定的截止时间
boolean awaitUntil(Date deadline) throws InterruptedException;
//唤醒一个等待的线程
void signal();
//唤醒所有的等待线程
void signalAll();
}

我们只需要将ReentranLockObj1 waitFun方法中添加lock即可,修改如下:

public void waitFun() {
        lock.lock();
        try {
            System.out.println("current thread name :" + Thread.currentThread().getName());
            condition.await();
            System.out.println("current thread name :" + Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

看看运行结果:
在这里插入图片描述
await方法后面的语句没有输入到控制台,处于等待状态。
进行通知唤醒:

public class ReentranLockObj2 {

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

    /**
     * 等待
     */
    public void waitFun() {
        lock.lock();
        try {
            System.out.println("current thread name:" + Thread.currentThread().getName());
            condition.await();
            System.out.println("current thread name:" + Thread.currentThread().getName());
        } catch (IllegalMonitorStateException | InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    /**
     * 唤醒
     */
    public void notifyFun() {
        lock.lock();
        try {
            condition.signal();
        } catch (IllegalMonitorStateException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }
}
public class ReentranLockObj1T2Main {

    public static void main(String[] args) throws InterruptedException {
        ReentranLockObj2 reentranLockObj2 = new ReentranLockObj2();
        ReentranLockObj2T2 reentranLockObj2T2 = new ReentranLockObj2T2(reentranLockObj2);
        reentranLockObj2T2.start();
        Thread.sleep(1000);
        reentranLockObj2.notifyFun();
    }
}

运行结果:
在这里插入图片描述
打印第一句,1秒之后打印第二句,使用signal()唤醒。唤醒所有等待中的线程,使用signalAll()

public class ReentranLockObj3 {

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

    public void waitFun1() {
        lock.lock();
        try {
            System.out.println("current thread name:" + Thread.currentThread().getName());
            condition.await();
            System.out.println("current thread name:" + Thread.currentThread().getName());
        } catch (IllegalMonitorStateException | InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void waitFun2() {
        lock.lock();
        try {
            System.out.println("current thread name:" + Thread.currentThread().getName());
            condition.await();
            System.out.println("current thread name:" + Thread.currentThread().getName());
        } catch (IllegalMonitorStateException | InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void notifyAllFun() {
        lock.lock();
        try {
            condition.signalAll();
        } catch (IllegalMonitorStateException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

}

线程1:

public class ReentranLockObj3T1 extends Thread {

    private ReentranLockObj3 reentranLockObj3;

    public ReentranLockObj3T1(ReentranLockObj3 reentranLockObj3, String threadName) {
        this.reentranLockObj3 = reentranLockObj3;
        this.setName(threadName);
    }

    @Override
    public void run() {
        reentranLockObj3.waitFun1();
    }
}

线程2:

public class ReentranLockObj3T2 extends Thread {

    private ReentranLockObj3 reentranLockObj3;

    public ReentranLockObj3T2(ReentranLockObj3 reentranLockObj3, String threadName) {
        this.reentranLockObj3 = reentranLockObj3;
        this.setName(threadName);
    }

    @Override
    public void run() {
        reentranLockObj3.waitFun2();
    }
}

运行结果:
在这里插入图片描述
先输出上面两行,等5分钟通过调用signalAll进行唤醒所有等待中的线程。
如果想单独唤醒一个,该怎么处理呢? 我们需要创建多个condition进行处理了。通过condition唤醒部分线程,可以有效提高程序运行效率。

public class ReentranLockObj4 {

    private Lock lock = new ReentrantLock();
    private Condition condition1 = lock.newCondition();
    private Condition condition2 = lock.newCondition();

    public void waitFunCondition1() {
        lock.lock();
        try {
            System.out.println("current thread name:" + Thread.currentThread().getName());
            condition1.await();
            System.out.println("current thread name:" + Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void waitFunCondition2() {
        lock.lock();
        try {
            System.out.println("current thread name:" + Thread.currentThread().getName());
            condition2.await();
            System.out.println("current thread name:" + Thread.currentThread().getName());
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void notifyFunCondition1() {
        lock.lock();
        try {
            condition1.signalAll();
        } catch (IllegalMonitorStateException e) {
            e.printStackTrace();
        } finally {

            lock.unlock();
        }
    }

    public void notifyFunCondition2() {
        lock.lock();
        try {
            condition2.signalAll();
        } catch (IllegalMonitorStateException e) {
            e.printStackTrace();
        } finally {

            lock.unlock();
        }
    }

}

线程1:

public class ReentranLockObj4T1 extends Thread {

    private ReentranLockObj4 reentranLockObj4;

    public ReentranLockObj4T1(ReentranLockObj4 reentranLockObj4, String threadName) {
        this.reentranLockObj4 = reentranLockObj4;
        this.setName(threadName);
    }

    @Override
    public void run() {
        reentranLockObj4.waitFunCondition1();
    }
}

线程2:

public class ReentranLockObj4T2 extends Thread {

    private ReentranLockObj4 reentranLockObj4;

    public ReentranLockObj4T2(ReentranLockObj4 reentranLockObj4, String threadName) {
        this.reentranLockObj4 = reentranLockObj4;
        this.setName(threadName);
    }

    @Override
    public void run() {
        reentranLockObj4.waitFunCondition2();
    }
}

运行:

public class ReentranLockObj4Main {

    public static void main(String[] args) throws InterruptedException {
        ReentranLockObj4 reentranLockObj4 = new ReentranLockObj4();
        ReentranLockObj4T1 reentranLockObj4T1 = new ReentranLockObj4T1(reentranLockObj4, "thread01");
        reentranLockObj4T1.start();
        ReentranLockObj4T2 reentranLockObj4T2 = new ReentranLockObj4T2(reentranLockObj4, "thread02");
        reentranLockObj4T2.start();
        Thread.sleep(5000);
        reentranLockObj4.notifyFunCondition1();
    }

}

运行结果:
在这里插入图片描述
有运行可以看出,当线程1唤醒的时候,调用线程1的wait后的方法,线程2没有调用,就还在等待中,程序没有结束。由此可以得出结论,ReentrantLock可以唤醒指定种类的线程。
总结一下:
1.Object类中的wait相当于Condition中的await
2.Object类中的wait(long timeout) 相当于Condition中的await(long timeout,TimeUnit unit)
3.Object类中的notify相当于Condition中的signal
4.Object类中的notifyAll相当于Condition中的signalAll

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值