zoukankan      html  css  js  c++  java
  • java-多线程的练习----妖,等待唤醒,代码重构,lock到condition

    1 需求

    资源有姓名和性别。

    两个线程,
        一个负责给姓名和性别赋值,
        一个负责获取姓名和性别的值。

    要求1,运行一下,解决程序的 "妖"的问题。

    要求2,实现正确数据的间隔输出 如
    张飞--男
    rose--女女女
    张飞--男
    rose--女女女

    要求3,对代码进行重构。
        将name,sex私有化,资源类提供对其访问的方法。

    要求4,将程序改成JDK1.5的Lock Condition接口。

    -------------------------------------

    2 妖的出现和解决

    原代码:

    //描述资源。
    class Resource
    {
    	String name;
    	String sex;
    }
    //赋值线程任务
    class Input implements Runnable
    {
    	private Resource r;
    //	private Object obj = new Object();
    	Input(Resource r)//任务一初始化就必须有要处理的资源。
    	{
    		this.r = r;
    	}
    	public void run()
    	{
    		int x = 0;
    		while(true)
    		{
    			{
    				if(x==0)
    				{
    					r.name = "张飞";
    					r.sex = "男";
    				}
    				else
    				{
    					r.name = "rose";
    					r.sex = "女女女女";
    				}
    			}
    			x = (x+1)%2;//实现切换。
    		}
    	}
    }
    //获取值线程任务
    class Output implements Runnable
    {
    	private Resource r ;
    //	private Object obj = new Object();
    	Output(Resource r)
    	{
    		this.r = r;
    	}
    	public void run()
    	{
    		while(true)
    		{
    			
    				System.out.println(r.name+"....."+r.sex);
    		}
    	}
    }
    
    class ThreadTest2
    {
    	public static void main(String[] args)
    	{
    		Resource r = new Resource();
    		Input in = new Input(r);
    		Output out = new Output(r);
    		Thread t1 = new Thread(in);
    		Thread t2 = new Thread(out);
    		t1.start();
    		t2.start();
    
    	}
    }
    

     测试结果: 会出现张飞.....女.或者是rose.....男,

     分析原因:假如某个时刻,name=rose,sex=女,进入if中,进行了name=张三后就停止了,不进行了sex的赋值,进入打印,这是时的name=张三,sex=女;

    解决方法:出现了安全问题.需要加入同步.详情请点击,

    //描述资源。
    class Resource
    {
        String name;
        String sex;
    }
    //赋值线程任务
    class Input implements Runnable
    {
        private Resource r;
    //    private Object obj = new Object();
        Input(Resource r)//任务一初始化就必须有要处理的资源。
        {
            this.r = r;
        }
        public void run()
        {
            int x = 0;
            while(true)
            {
                synchronized(r) //加入同步
                {
                    if(x==0)
                    {
                        r.name = "张飞";
                        r.sex = "男";
                    }
                    else
                    {
                        r.name = "rose";
                        r.sex = "女女女女";
                    }
                }
                x = (x+1)%2;//实现切换。
            }
        }
    }
    //获取值线程任务
    class Output implements Runnable
    {
        private Resource r ;
    //    private Object obj = new Object();
        Output(Resource r)
        {
            this.r = r;
        }
        public void run()
        {
            while(true)
            {
                synchronized(r)  //加入同步
                {
                    System.out.println(r.name+"....."+r.sex);
                }
            }
        }
    }
    
    class ThreadTest2
    {
        public static void main(String[] args)
        {
            Resource r = new Resource();
            Input in = new Input(r);
            Output out = new Output(r);
            Thread t1 = new Thread(in);
            Thread t2 = new Thread(out);
            t1.start();
            t2.start();
    
        }
    }

    测试结果

    -------------------------------------

    3 等待唤醒

     出现问题:由上面的结果可知,出现了大量的男或女,没有出现一男一女

    解决问题:加入等待唤醒.输入后等待,唤醒输出,输出后,唤醒输入;一般要加入个标志

    //描述资源。
    class Resource
    {
        String name;
        String sex;
        //定义标记,
        boolean flag = false;
    
    }
    //赋值线程任务
    class Input implements Runnable
    {
        private Resource r;
    //    private Object obj = new Object();
        Input(Resource r)//任务一初始化就必须有要处理的资源。
        {
            this.r = r;
        }
        public void run()
        {
            int x = 0;
            while(true)
            {
                synchronized(r)
                {
                    if(r.flag)
                        try{r.wait();}catch(InterruptedException e){}//等待唤醒机制
                    if(x==0)
                    {
                        r.name = "张飞";
                        r.sex = "男";
                    }
                    else
                    {
                        r.name = "rose";
                        r.sex = "女女女女";
                    }
    
                    r.flag = true;
                    r.notify();   //等待唤醒机制
                }
                x = (x+1)%2;//实现切换。
            }
        }
    }
    //获取值线程任务
    class Output implements Runnable
    {
        private Resource r ;
    //    private Object obj = new Object();
        Output(Resource r)
        {
            this.r = r;
        }
        public void run()
        {
            while(true)
            {
                synchronized(r)
                {
                    if(!r.flag)//等待唤醒机制
                        try{r.wait();}catch(InterruptedException e){}
                    System.out.println(r.name+"....."+r.sex);
                    r.flag = false;
                    r.notify();//等待唤醒机制
                }
            }
        }
    }
    
    class ThreadTest2_2
    {
        public static void main(String[] args)
        {
            Resource r = new Resource();
            Input in = new Input(r);
            Output out = new Output(r);
            Thread t1 = new Thread(in);
            Thread t2 = new Thread(out);
            t1.start();
            t2.start();
    
        }
    }

    测试结果

    -------------------------------------

     4 代码重构

    解决问题:将name,sex私有化,资源类提供对其访问的方法。这时加同步要放在共有资源里面

    //描述资源。
    class Resource
    {
        private String name;   //
        private String sex;   //代码重构
        //定义标记,
        private boolean flag = false;
    
        //赋值功能。
        public synchronized void set(String name,String sex)// //代码重构 
        {
            if(flag)
                try{this.wait();}catch(InterruptedException e){}
            this.name = name;
            this.sex = sex;
            flag = true;
            this.notify();
        }
    
        //获取值。
        public synchronized void out()
        {
            if(!flag)
                try{this.wait();}catch(InterruptedException e){}
            System.out.println(name+"------"+sex);
            flag = false;
            this.notify();
        }
    
    }
    //赋值线程任务
    class Input implements Runnable
    {
        private Resource r;
        Input(Resource r)//任务一初始化就必须有要处理的资源。
        {
            this.r = r;
        }
        public void run()
        {
            int x = 0;
            while(true)
            {
                if(x==0)
                {
                    r.set("张飞","男");
                }
                else
                {
                    r.set("rose","女女女女");
                }
                x = (x+1)%2;//实现切换。
            }
        }
    }
    //获取值线程任务
    class Output implements Runnable
    {
        private Resource r ;
        Output(Resource r)
        {
            this.r = r;
        }
        public void run()
        {
            while(true)
            {
                    r.out();
            }
        }
    }
    
    class ThreadTest2_3
    {
        public static void main(String[] args)
        {
            Resource r = new Resource();
            Input in = new Input(r);
            Output out = new Output(r);
            Thread t1 = new Thread(in);
            Thread t2 = new Thread(out);
            t1.start();
            t2.start();
    
        }
    }

    -------------------------------------

    5,将程序改成JDK1.5的Lock Condition接口

    解决问题:Lock替换了 同步函数或者同步代码块。Condition替代了 监视器方法,将监视器方法从锁上分离出来,单独封装成Condition对象。

    import java.util.concurrent.locks.*;
    //描述资源。
    class Resource
    {
        private String name;
        private String sex;                                          //程序改成JDK1.5的Lock Condition接口
        //定义标记,
        private boolean flag = false;
    
        //先创建锁对象。
        private final Lock lock = new ReentrantLock();//
    
        //通过锁对象获取监视器对象。
        private Condition con = lock.newCondition();//
        
        //赋值功能。
        public  void set(String name,String sex)
        {
            lock.lock();//
            try{
                if(flag)
                    try{con.await();}catch(InterruptedException e){}//
                this.name = name;
                this.sex = sex;
                flag = true;
                con.signal();//
            }finally{
                lock.unlock();//
            }
        }
    
        //获取值。
        public  void out()
        {
            lock.lock();//
            try{
                if(!flag)
                    try{con.await();}catch(InterruptedException e){}//
                System.out.println(name+"------"+sex);
                flag = false;
                con.signal();//
            }finally{
                lock.unlock();//
            }
        }
    
    }
    //赋值线程任务
    class Input implements Runnable
    {
        private Resource r;
        Input(Resource r)//任务一初始化就必须有要处理的资源。
        {
            this.r = r;
        }
        public void run()
        {
            int x = 0;
            while(true)
            {
                if(x==0)
                {
                    r.set("张飞","男");
                }
                else
                {
                    r.set("rose","女女女女");
                }
                x = (x+1)%2;//实现切换。
            }
        }
    }
    //获取值线程任务
    class Output implements Runnable
    {
        private Resource r ;
        Output(Resource r)
        {
            this.r = r;
        }
        public void run()
        {
            while(true)
            {
                    r.out();
            }
        }
    }
    
    class ThreadTest2_4
    {
        public static void main(String[] args)
        {
            Resource r = new Resource();
            Input in = new Input(r);
            Output out = new Output(r);
            Thread t1 = new Thread(in);
            Thread t2 = new Thread(out);
            t1.start();
            t2.start();
    
        }
    }


    作者:8亩田
    本文版权归作者和博客园共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接.

    本文如对您有帮助,还请多帮 【推荐】 下此文。
    如果喜欢我的文章,请关注我的公众号
    如果有疑问,请下面留言

    学而不思则罔 思而不学则殆
  • 相关阅读:
    【机器学习】转导推理——Transductive Learning
    【机器学习】Learning to Rank入门小结 + 漫谈
    【机器学习】Learning to Rank入门小结 + 漫谈
    【机器学习】Learning to Rank 简介
    【机器学习】Learning to Rank 简介
    【机器学习】Learning to Rank之Ranking SVM 简介
    【机器学习】Learning to Rank之Ranking SVM 简介
    【计算机视觉】背景建模--Vibe 算法优缺点分析
    【计算机视觉】背景建模--Vibe 算法优缺点分析
    【机器学习】Jackknife,Bootstraping, bagging, boosting, AdaBoosting, Rand forest 和 gradient boosting
  • 原文地址:https://www.cnblogs.com/liu-wang/p/6083109.html
Copyright © 2011-2022 走看看