线程通信之等待通知机制

等待通知机制模式是java中比较经典的线程通信方式,两个线程通过对同一对象调用等待 wait() 和通知 notify() 方法来进行通讯。
例:两个线程从集合中获取数据

@Slf4j
public class ThreadWaitNotify {

    private static final List<Integer> list = Lists.newArrayList(2, 15, 5, 4, 8, 17, 23, 24, 43, 50, 57, 31);

    private static int index = 0;

    public static void main(String[] args) {
        new Thread(new OneThread()).start();
        new Thread(new TwoThread()).start();
        log.debug("main treand 执行完毕");
    }

    public static class OneThread implements Runnable {
        @Override
        public void run() {
            while (ThreadWaitNotify.index < list.size()) {
                synchronized (ThreadWaitNotify.class) {
                    log.info("OneThread抢到锁,index为[{}]", index);
                    //满足条件执行逻辑
                    if (index % 2 == 0) {
                        log.info("OneThread取出数据[{}]", list.get(index));
                        index++;
                        //将等待队列中的线程移动到同步队列中,线程状态也会更新为 BLOCKED
                        ThreadWaitNotify.class.notify();
                    } else {
                        try {
                            //释放锁,进入 WAITING 状态,该线程也会被移动到等待队列中
                            log.info("OneThread释放锁");
                            ThreadWaitNotify.class.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }

    public static class TwoThread implements Runnable {
        @Override
        public void run() {
            while (ThreadWaitNotify.index < list.size()) {
                synchronized (ThreadWaitNotify.class) {
                    log.info("TwoThread抢到锁,index为[{}]", index);
                    //满足条件执行逻辑
                    if (index % 2 != 0) {
                        log.info("TwoThread取出数据[{}]", list.get(index));
                        index++;
                        ThreadWaitNotify.class.notify();
                    } else {//释放锁,进入 WAITING 状态,该线程也会被移动到等待队列中
                        try {
                            log.info("TwoThread释放锁");
                            ThreadWaitNotify.class.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
            }
        }
    }
}

输出结果:
10:36:48.242 [Thread-0] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - OneThread抢到锁,index为[0]
10:36:48.249 [Thread-0] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - OneThread取出数据[2]
10:36:48.249 [Thread-0] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - OneThread抢到锁,index为[1]
10:36:48.249 [Thread-0] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - OneThread释放锁
10:36:48.250 [Thread-1] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - TwoThread抢到锁,index为[1]
10:36:48.250 [Thread-1] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - TwoThread取出数据[15]
10:36:48.250 [Thread-1] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - TwoThread抢到锁,index为[2]
10:36:48.250 [Thread-1] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - TwoThread释放锁
10:36:48.250 [Thread-0] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - OneThread抢到锁,index为[2]
10:36:48.250 [Thread-0] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - OneThread取出数据[5]
10:36:48.250 [Thread-1] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - TwoThread抢到锁,index为[3]
10:36:48.250 [Thread-1] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - TwoThread取出数据[4]
10:36:48.250 [Thread-1] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - TwoThread抢到锁,index为[4]
10:36:48.250 [Thread-1] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - TwoThread释放锁
10:36:48.250 [Thread-0] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - OneThread抢到锁,index为[4]
10:36:48.250 [Thread-0] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - OneThread取出数据[8]
10:36:48.250 [Thread-1] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - TwoThread抢到锁,index为[5]
10:36:48.250 [Thread-1] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - TwoThread取出数据[17]
10:36:48.251 [Thread-1] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - TwoThread抢到锁,index为[6]
10:36:48.251 [Thread-1] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - TwoThread释放锁
10:36:48.251 [Thread-0] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - OneThread抢到锁,index为[6]
10:36:48.251 [Thread-0] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - OneThread取出数据[23]
10:36:48.251 [Thread-1] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - TwoThread抢到锁,index为[7]
10:36:48.251 [Thread-1] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - TwoThread取出数据[24]
10:36:48.251 [Thread-1] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - TwoThread抢到锁,index为[8]
10:36:48.251 [Thread-1] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - TwoThread释放锁
10:36:48.251 [Thread-0] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - OneThread抢到锁,index为[8]
10:36:48.251 [Thread-0] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - OneThread取出数据[43]
10:36:48.251 [Thread-1] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - TwoThread抢到锁,index为[9]
10:36:48.251 [Thread-1] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - TwoThread取出数据[50]
10:36:48.251 [Thread-1] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - TwoThread抢到锁,index为[10]
10:36:48.251 [Thread-1] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - TwoThread释放锁
10:36:48.251 [Thread-0] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - OneThread抢到锁,index为[10]
10:36:48.251 [Thread-0] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - OneThread取出数据[57]
10:36:48.251 [Thread-1] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - TwoThread抢到锁,index为[11]
10:36:48.251 [Thread-1] INFO com.lei.tang.java8.thread.communication.ThreadWaitNotify - TwoThread取出数据[31]
10:36:48.252 [main] DEBUG com.lei.tang.java8.thread.communication.ThreadWaitNotify - main treand 执行完毕

OneThread和TwoThread都对同一对象ThreadWaitNotify.class获取锁,OneThread先获取到锁,由于该锁已经被占用,所以TwoThread只能等待这把锁,这时候TwoThread将会进入这把锁的锁池,OneThread执行完逻辑后,将唤醒TwoThread进入同步队列中,也就是锁池中,当OneThread线程不满足时,则会调用ThreadWaitNotify.class.wait()方法,释放锁并进入等待池中,由此相互唤醒达到等待通知机制。

在这个例子中我们利用了对象内部锁达到等待通知机制机制,下面就对象内部锁作出简单的介绍:每个对象都拥有两个池,分别为锁池(EntrySet)和(WaitSet)等待池。

  • 锁池:假如已经有线程A获取到了锁,这时候又有线程B需要获取这把锁(比如需要调用synchronized修饰的方法或者需要执行synchronized 修饰的代码块),由于该锁已经被占用,所以线程B只能等待这把锁,这时候线程B将会进入这把锁的锁池。

  • 等待池:假设线程A获取到锁之后,由于一些条件的不满足(例如生产者消费者模式中生产者获取到锁,然后判断队列为满),此时需要调用对象锁的wait方法,那么线程A将放弃这把锁,并进入这把锁的等待池。

  • 如果有其他线程调用了锁的notify方法,则会根据一定的算法从等待池中选取一个线程,将此线程放入锁池。

  • 如果有其他线程调用了锁的notifyAll方法,则会将等待池中所有线程全部放入锁池,并争抢锁。

  • 锁池与等待池的区别:等待池中的线程不能获取锁,而是需要被唤醒进入锁池,才有获取到锁的机会。

  • wait() 、notify()、notifyAll() 调用的前提都是获得了对象的锁(也可称为对象监视器)。 调用 wait()

  • 方法后线程会释放锁,进入 WAITING 状态,该线程也会被移动到等待队列中。 调用 notify()

  • 方法会将等待队列中的线程移动到同步队列中,线程状态也会更新为 BLOCKED 从 wait() 方法返回的前提是调用 notify()

  • 方法的线程释放锁,wait() 方法的线程获得锁。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值