前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Java并发-被动使线程wait/notify

Java并发-被动使线程wait/notify

作者头像
Fisherman渔夫
发布2020-02-18 16:29:27
4610
发布2020-02-18 16:29:27
举报
文章被收录于专栏:渔夫渔夫

一、介绍

 此任务的目标是安全、高效地使一个运行着的线程开始进入wait状态以及从wait状态中唤醒。而此操作都是通过其他线程被动地使当前线程将运行状态的强制转换,具体实现方式不妨就从代码出发吧!

二、代码示例

import java.util.concurrent.atomic.AtomicInteger;

/**
 * 实现线程的被动wait,依靠其余线程发出信号进行线程的wait\notify,而不是本身根据线程数目的限定而控制等待和wait.
 *
 * 以下toWait方法为将当前线程置为wait状态
 * toNotify 方法为将当前线程置为唤醒状态
 *
 * 其中有一个大区别就是一个方法需要同步监视代码块,而另一个不需要
 */
public class PessimisticWait {
    static final Object MONITOR = new Object();
    static AtomicInteger i = new AtomicInteger();

    public static void main(String[] args) {
        ThreadTest threadTest = new ThreadTest();
        threadTest.start();

        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        threadTest.toWait();

        try {
            Thread.sleep(2000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }

        threadTest.toNotify();



        try {
            Thread.sleep(1000);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        threadTest.toWait();


    }

    static class ThreadTest extends Thread {
        private boolean flag = false;

        @Override
        public void run() {

            System.out.println("线程进入第一次运行状态");
            while (true) {
                synchronized (MONITOR) {

                    if (flag) {
                        try {
                            System.out.println("线程开始wait");

                            MONITOR.wait();
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                    }
                }
                try {
                    Thread.sleep(100);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                i.getAndIncrement();

                System.out.println("当前线程正再执行" + i);
            }


        }

        public void toWait() {

            flag = true;
        }

        public void toNotify(){

            synchronized (MONITOR){
                flag =false;
                MONITOR.notify();
                System.out.println("线程wait结束,唤醒线程");

            }

        }


    }
}

控制台输出:

线程进入第一次运行状态
当前线程正再执行1
当前线程正再执行2
当前线程正再执行3
当前线程正再执行4
当前线程正再执行5
当前线程正再执行6
当前线程正再执行7
当前线程正再执行8
当前线程正再执行9
当前线程正再执行10
线程开始wait
线程wait结束,唤醒线程
当前线程正再执行11
当前线程正再执行12
当前线程正再执行13
当前线程正再执行14
当前线程正再执行15
当前线程正再执行16
当前线程正再执行17
当前线程正再执行18
当前线程正再执行19
当前线程正再执行20
线程开始wait

三、代码分析

代码实现的功能:上述代码实现了在main线程中将ThreadTest线程对象通过waitf方法强制进入阻塞状态以及通过notify方法唤醒。

注意事项toWait()toNotify()方法实现了当前线程的进入wait状态以及唤醒操作。但是我问读者朋友们一个问题:为何前者没有使用synchronized,而后者却需要呢?

 首先,我们wait方法一般通过监视器对象来进行调用,如果在toWait()中使用synchronized关键字进行监视器同步代码块处理,那么在main方法中调用时,当前线程为main线程,这样一来只会错将main线程阻塞。所以我们设计一个flag来控制是否使threadTest对象自己来调用wait方法,这就保证了阻塞线程对象的正确性。

 其次,当前由于释放MONITOR对象而阻塞的线程只有一个,即threadTest对象,所以我们只需在同步监视器内调用 MONITOR.notify();方法即能唤醒threadTest线程,并且此方法不与当前运行的线程有关,所以需要在toNotify方法内部上锁时即使当前线程是main线程,也是没有影响的。

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 一、介绍
  • 二、代码示例
  • 三、代码分析
相关产品与服务
腾讯云代码分析
腾讯云代码分析(内部代号CodeDog)是集众多代码分析工具的云原生、分布式、高性能的代码综合分析跟踪管理平台,其主要功能是持续跟踪分析代码,观测项目代码质量,支撑团队传承代码文化。
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档