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();

    }
}

 

posted @ 2016-11-20 18:28  8亩田  阅读(325)  评论(0编辑  收藏  举报