Java自学者论坛

 找回密码
 立即注册

手机号码,快捷登录

恭喜Java自学者论坛(https://www.javazxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,会员资料板块,购买链接:点击进入购买VIP会员

JAVA高级面试进阶训练营视频教程

Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程Go语言视频零基础入门到精通Java架构师3期(课件+源码)
Java开发全终端实战租房项目视频教程SpringBoot2.X入门到高级使用教程大数据培训第六期全套视频教程深度学习(CNN RNN GAN)算法原理Java亿级流量电商系统视频教程
互联网架构师视频教程年薪50万Spark2.0从入门到精通年薪50万!人工智能学习路线教程年薪50万大数据入门到精通学习路线年薪50万机器学习入门到精通教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程MySQL入门到精通教程
查看: 439|回复: 0

Java多线程间通信-解决安全问题、等待唤醒机制

[复制链接]
  • TA的每日心情
    奋斗
    2024-4-6 11:05
  • 签到天数: 748 天

    [LV.9]以坛为家II

    2034

    主题

    2092

    帖子

    70万

    积分

    管理员

    Rank: 9Rank: 9Rank: 9

    积分
    705612
    发表于 2021-9-5 13:16:17 | 显示全部楼层 |阅读模式



    /*
    1.增加一个知识点
    一个类怎么在所有的类中,让其它类来共同修改它的数据呢?
    可以用单例设计模式
    可以用静态
    可以在其它类中做一个构造函数,接受同一个对象,这样就可以实现对象

    2.状态选择
    可以用数字0 1 判断
    可以用bool
    注意变量的范围即可

    3.加了同步后,还是有安全怎么办?
    想前提!  1.  两个及以上线程(同步的)  2.操作公用资源  3.要用同一锁
    */

    /*
    线程间通讯:
    其实就是多个线程在操作同一个资源,
    但是操作的动作不同。

    */



    /*
    1.为什么会出现安全问题?
    就是不满足前提呗

    2.我们还没有了解到线程的本质
    1.线程的执行时互相争抢执行权的
    2.如果没有同步代码块的话,就会对数据进行胡乱修改,有可能修改到一半,另一个线程进来,有可能修改好几次,等等,甚至还会无视条件
    3.即便有了同步代码块,也不能保证代码是按次序相互执行,因为,第一个线程执行完之后,还会参与下一次的争抢当中来,拥有相同的争抢概率
    所以就出现同步中的不同步状况,这时候就要用到唤醒
    4.其实程序就是一个逻辑判断问题,就是看有没有数据
    */


    /*五种状态之一的等待
    1.是Thread从上帝那里继承来的
    2.而且这个函数是抛了异常的,根据异常的格式,要try和catch
    3.唤醒也是继承上帝的
    4.使用的时候,直接用对象点出来就可以
    5.这样很容易区分,也造成为什么要把这两个函数写在上帝里面的原因,锁是任意类型的,什么对象都可以

    */
    class Res                                   /*定义一个类,里面封装好数据成员,用来去调用*/
    {
        String name;
        String sex;
        boolean flag = false;      /*用来判断是否已经存入数据,封装好用来调用*/
    }

    class Input implements Runnable
    {
        private Res r ;
        Input(Res r)
        {
            this.r = r;
        }
        public void run()
        {
            int x = 0;
            while(true)
            {
                synchronized(r)             /*只能让一个线程进来,而且输入的先进来,输出的就不给进了,这样就满足了前提,有两个线程,同一锁,公共资源*/
                {

                    if(r.flag)               /*真,冻结*/
                        try{r.wait();}catch(Exception e){}     /*线程池,等待线程都在线程池当中,唤醒的是什么,唤醒的都是线程池当中的线程*/
                    if(x==0)
                    {
                        r.name="mike";                    /*赋值*/
                        r.sex="man";
                    }
                    else
                    {
                        r.name="丽丽";
                        r.sex = "女女女女女";
                    }
                    x = (x+1)%2;               /*转换性别*/
                    r.flag = true;    
                    r.notify();       /*有就唤醒,没有就不唤醒,按顺序来自然就不需要这个,唤醒的是另一个线程*/
                }
            }
        }
    }

    class Output implements Runnable
    {
        private Res r ;            /*对象数据成员*/
        
        Output(Res r)
        {
            this.r = r;                  /*传递对象进来*/
        }
        public void run()
        {
            while(true)
            {
                synchronized(r)             /*放的是对象*/
                {
                    if(!r.flag)
                        try{r.wait();}catch(Exception e){}
                    System.out.println(r.name+"...."+r.sex);            /*删除*/
                    r.flag = false;    
                    r.notify();                                 /*唤醒输入线程*/
                }
            }
        }
    }


    class  InputOutputDemo
    {
        public static void main(String[] args)
        {
            Res r = new Res();                     /*封装好的类,将会当作参数,传递给其它类*/

            Input in = new Input(r);               /*实现多线程类的对象*/
            Output out = new Output(r);

            Thread t1 = new Thread(in);          /*开启线程,把实现线程的对象放进来*/
            Thread t2 = new Thread(out);

            t1.start();                  /*开启线程,调用run函数*/
            t2.start();
        }
    }


    //notifyAll();

    /*
    wait:
    notify();
    notifyAll();

    都使用在同步中,因为要对持有监视器(锁)的线程操作。
    所以要使用在同步中,因为只有同步才具有锁。

    为什么这些操作线程的方法要定义Object类中呢?
    因为这些方法在操作同步中线程时,都必须要标识它们所操作线程只有的锁,
    只有同一个锁上的被等待线程,可以被同一个锁上notify唤醒。
    不可以对不同锁中的线程进行唤醒。

    也就是说,等待和唤醒必须是同一个锁。

    而锁可以是任意对象,所以可以被任意对象调用的方法定义Object类中。


    */


    代码优化:
    /*
    线程间通讯:
    其实就是多个线程在操作同一个资源,
    但是操作的动作不同。

    */
    class Res
    {
        private String name;
        private String sex;
        private boolean flag = false;

        public synchronized void set(String name,String sex)
        {
            if(flag)
                try{this.wait();}catch(Exception e){}             /*记住,加同步的是共同操作的数据,不是定义数据,是会变动的数据*/
            this.name = name;
            
            this.sex = sex;
            flag = true;
            this.notify();                                       /*this代表同步函数的锁,也代表当前对象*/
        }
        public synchronized void out()
        {
            if(!flag)
                try{this.wait();}catch(Exception e){}
            System.out.println(name+"........"+sex);
            flag = false;
            this.notify();
        }
    }

    class Input implements Runnable
    {
        private Res r ;                 /*用来接收同一个对象*/
        Input(Res r)
        {
            this.r = r;
        }
        public void run()
        {
            int x = 0;
            while(true)
            {
                if(x==0)                
                    r.set("mike","man");    /*这个函数已经是同步函数了*/            
                else    
                    r.set("丽丽","女女女女女");                
                x = (x+1)%2;
            }
        }
    }

    class Output implements Runnable
    {
        private Res r ;
        
        Output(Res r)
        {
            this.r = r;
        }
        public void run()
        {
            while(true)
            {
                r.out();       /*不断输出*/
            }
        }
    }


    class  InputOutputDemo2
    {
        public static void main(String[] args)
        {
            Res r = new Res();

            new Thread(new Input(r)).start();            /*全部使用无名对象,优化代码*/
            new Thread(new Output(r)).start();
            /*
            Input in = new Input(r);
            Output out = new Output(r);

            Thread t1 = new Thread(in);
            Thread t2 = new Thread(out);

            t1.start();
            t2.start();
            */
        }
    }






    哎...今天够累的,签到来了1...
    回复

    使用道具 举报

    您需要登录后才可以回帖 登录 | 立即注册

    本版积分规则

    QQ|手机版|小黑屋|Java自学者论坛 ( 声明:本站文章及资料整理自互联网,用于Java自学者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

    GMT+8, 2024-5-4 23:20 , Processed in 0.086905 second(s), 29 queries .

    Powered by Discuz! X3.4

    Copyright © 2001-2021, Tencent Cloud.

    快速回复 返回顶部 返回列表