前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >ReentrantLock类与Condition类的结合使用

ReentrantLock类与Condition类的结合使用

作者头像
吉林乌拉
发布2019-08-14 17:49:06
1.7K0
发布2019-08-14 17:49:06
举报
文章被收录于专栏:吉林乌拉吉林乌拉

我们在上一篇简单介绍了ReentrantLock类的基本使用,也就是获取锁,与释放锁。那如果我们要实现wait()和notify()等待通知的功能在ReentrantLock类中我们应该怎么办呢。这时我们就要借助一个新类了,它就是Condition类。Condition类也是JDK1.5以后新增的类。它可以实现多路通知功能,也就是说在一个Lock对象中可以创建多个Condition类相当于有多个锁对象,通知的时候可以选择性的进行线程通知,而不是notify()那样是由CPU随机决定通知的是哪个线程,Condition类使它在线程调度上更加灵活。下面我们看一下具体的事例。

代码语言:javascript
复制
/**
 * 用户登录
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-15 10:35
 * @since 1.0.0
 */
public class Userinfo {

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

    public void await() {
        try {
            lock.lock();
            System.out.println(String.format("线程开始\tthread: %s", Thread.currentThread().getName()));
            condition.await();
            System.out.println(String.format("线程结束\tthread: %s", Thread.currentThread().getName()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void signal() {
        lock.lock();
        System.out.println(String.format("线程恢复\tthread: %s", Thread.currentThread().getName()));
        condition.signal();
        lock.unlock();
    }
}
代码语言:javascript
复制
/**
 * 管理用户请求
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-15 10:44
 * @since 1.0.0
 */
public class RequestAdmin extends Thread {

    private Userinfo userinfo;


    public RequestAdmin(Userinfo userinfo) {
        this.userinfo = userinfo;
    }

    @Override
    public void run() {
        userinfo.await();
    }
}
代码语言:javascript
复制
/**
 * 用户请求
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-15 10:44
 * @since 1.0.0
 */
public class RequestUser extends Thread {

    private Userinfo userinfo;

    public RequestUser(Userinfo userinfo) {
        this.userinfo = userinfo;
    }

    @Override
    public void run() {
        userinfo.signal();
    }
}
代码语言:javascript
复制
/**
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-20 13:35
 * @since 1.0.0
 */
public class Test {
    public static void main(String[] args) throws InterruptedException {
        Userinfo userinfo = new Userinfo();
        RequestAdmin requestAdmin = new RequestAdmin(userinfo);
        RequestUser requestUser = new RequestUser(userinfo);
        requestAdmin.start();
        Thread.sleep(1000);
        for (int i = 3; i > 0; i--) {
            System.out.println(String.format("倒计时:%s", i));
            Thread.sleep(1000);
        }
        requestUser.start();
    }
}
代码语言:javascript
复制
线程开始	thread: Thread-0
倒计时:3
倒计时:2
倒计时:1
线程恢复	thread: Thread-1
线程结束	thread: Thread-0

我们用ReentrantLock和Condition类成功实现了wait()和notify()暂停与通知的功能。使用还是比较简单,和以前的wait()、notify()方法使用基本一致。

代码语言:javascript
复制
condition.await(); // 相当于wait()方法
代码语言:javascript
复制
condition.signal();// 相当于notify()方法

我们知道用notifyAll()方法可以恢复暂停的所有线程,同样Condition类中也有同样的方法实现了该逻辑,只是方法不叫notifyAll()而是叫signalAll()方法。请看下面事例。

代码语言:javascript
复制
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 用户登录
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-15 10:35
 * @since 1.0.0
 */
public class Userinfo {

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

    public void await1() {
        try {
            lock.lock();
            System.out.println(String.format("await1线程开始\tthread: %s", Thread.currentThread().getName()));
            condition.await();
            System.out.println(String.format("await1线程结束\tthread: %s", Thread.currentThread().getName()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void await2() {
        try {
            lock.lock();
            System.out.println(String.format("await2线程开始\tthread: %s", Thread.currentThread().getName()));
            condition.await();
            System.out.println(String.format("await2线程结束\tthread: %s", Thread.currentThread().getName()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void signalAll() {
        lock.lock();
        System.out.println(String.format("恢复所有线程\tthread: %s", Thread.currentThread().getName()));
        condition.signalAll();
        lock.unlock();
    }
}
代码语言:javascript
复制
/**
 * 管理用户请求
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-15 10:44
 * @since 1.0.0
 */
public class RequestAdmin extends Thread {

    private Userinfo userinfo;


    public RequestAdmin(Userinfo userinfo) {
        this.userinfo = userinfo;
    }

    @Override
    public void run() {
        userinfo.await1();
    }
}
代码语言:javascript
复制
/**
 * 用户请求
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-15 10:44
 * @since 1.0.0
 */
public class RequestUser extends Thread {

    private Userinfo userinfo;

    public RequestUser(Userinfo userinfo) {
        this.userinfo = userinfo;
    }

    @Override
    public void run() {
        userinfo.await2();
    }
}
代码语言:javascript
复制
/**
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-20 13:35
 * @since 1.0.0
 */
public class Test {
    public static void main(String[] args) throws InterruptedException {
        Userinfo userinfo = new Userinfo();
        RequestAdmin requestAdmin = new RequestAdmin(userinfo);
        RequestUser requestUser = new RequestUser(userinfo);
        requestAdmin.start();
        requestUser.start();
        Thread.sleep(1000);
        for (int i = 3; i > 0; i--) {
            System.out.println(String.format("倒计时:%s", i));
            Thread.sleep(1000);
        }
        userinfo.signalAll();
    }
}
代码语言:javascript
复制
await1线程开始	thread: Thread-0
await2线程开始	thread: Thread-1
倒计时:3
倒计时:2
倒计时:1
恢复所有线程	thread: main
await1线程结束	thread: Thread-0
await2线程结束	thread: Thread-1

我们看因为调用了signalAll()方法,所以所有暂停的线程都被恢复了。这和notifyAll()方法一样,没什么好说的。但如果我们想要实现恢复指定的线程那应该怎么办呢?我们知道调用notifyAll()方法恢复哪个线程是由CPU决定的,我们程序是控制不了的,这时有人可能会想到设置线程的优先级来实现让指定的线程优先执行。但这还不是绝对的。设置优先级也是说明那个线程获取执行的概率比较大,还是不能保证百分之百执行的。虽然用notifyAll()方法没有什么简单的办法让指定的线程恢复执行,但在Condition类中确可以很方便的实现此功能,这也是Condition类可以实现多路通知功能的体现。下面我们来演示一下用Condition类怎么实现我们上述的需求。

代码语言:javascript
复制
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * 用户登录
 *
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-15 10:35
 * @since 1.0.0
 */
public class Userinfo {

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

    public void await1() {
        try {
            lock.lock();
            System.out.println(String.format("await1线程开始\tthread: %s", Thread.currentThread().getName()));
            condition1.await();
            System.out.println(String.format("await1线程结束\tthread: %s", Thread.currentThread().getName()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void await2() {
        try {
            lock.lock();
            System.out.println(String.format("await2线程开始\tthread: %s", Thread.currentThread().getName()));
            condition2.await();
            System.out.println(String.format("await2线程结束\tthread: %s", Thread.currentThread().getName()));
        } catch (InterruptedException e) {
            e.printStackTrace();
        } finally {
            lock.unlock();
        }
    }

    public void signalAll1() {
        lock.lock();
        System.out.println(String.format("恢复所有线程\tthread: %s", Thread.currentThread().getName()));
        condition1.signalAll();
        lock.unlock();
    }

    public void signalAll2() {
        lock.lock();
        System.out.println(String.format("恢复所有线程\tthread: %s", Thread.currentThread().getName()));
        condition2.signalAll();
        lock.unlock();
    }
}
代码语言:javascript
复制
/**
 * @author Sama
 * @author admin@jilinwula.com
 * @date 2017-03-20 13:35
 * @since 1.0.0
 */
public class Test {
    public static void main(String[] args) throws InterruptedException {
        Userinfo userinfo = new Userinfo();
        RequestAdmin requestAdmin = new RequestAdmin(userinfo);
        RequestUser requestUser = new RequestUser(userinfo);
        requestAdmin.start();
        requestUser.start();
        Thread.sleep(1000);
        for (int i = 3; i > 0; i--) {
            System.out.println(String.format("倒计时:%s", i));
            Thread.sleep(1000);
        }
        userinfo.signalAll1();
    }
}
代码语言:javascript
复制
await1线程开始	thread: Thread-0
await2线程开始	thread: Thread-1
倒计时:3
倒计时:2
倒计时:1
恢复所有线程	thread: main
await1线程结束	thread: Thread-0

我们看这时就实现了我们上述的需求。用Condition类可以唤醒我们指定的线程,确实比notify()更简单更方便。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-05-11,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 吉林乌拉 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档