5-1-Java多线程-练习-妖的出现和解决

本文探讨了多线程环境下共享资源的同步问题,通过不同方法解决了线程间的数据竞争和有序输出问题,包括使用synchronized关键字、等待唤醒机制、重构资源类以及采用Lock和Condition接口。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

妖的出现和解决

需求

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

    1. 要求1,运行一下,解决程序的 “妖”的问题。
      分析过程:
      加入同步,必须保证同一个锁,解决妖的问题。

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

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

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

代码示例-需要分析的代码

代码


//描述资源。
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.....女女女女
rose.....女女女女
张飞.....女女女女
张飞.....女女女女
rose.....男
rose.....女女女女
rose.....女女女女
张飞.....女女女女
rose.....女女女女
rose.....女女女女
张飞.....男
张飞.....男
rose.....女女女女

 分析

操作共享数据 name 和 sex

假设在–>处切换CPU执行权

if(x==0)
{
    r.name = "张飞";
    -->
    r.sex = "男";
}
else
{
    r.name = "rose";
    -->
    r.sex = "女女女女";
}

解决问题1

要求1,运行一下,解决程序的 “妖”的问题。
分析过程:
加入同步,必须保证同一个锁,解决妖的问题

代码示例

注意使用resouce做锁.(同步输入输出两个动作)

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

    }
}

运行结果

rose.....女女女女
rose.....女女女女
rose.....女女女女
rose.....女女女女
rose.....女女女女
rose.....女女女女
rose.....女女女女
rose.....女女女女
张飞.....男
张飞.....男
张飞.....男
张飞.....男
张飞.....男
张飞.....男
张飞.....男
张飞.....

解决问题2

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

代码

使用等待唤醒机制,使用flag作为判断是否等待

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

    }
}

解决问题3

  1. 要求3,对代码进行重构。
    将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();

    }
}

解决问题4

要求4,将程序改成JDK1.5的Lock Condition接口。
Lock替换了 同步函数或者同步代码块。
Condition替代了 监视器方法,将监视器方法从锁上分离出来,单独封装成Condition对象。

代码示例

class Resource
{
    private String name;
    private String sex;
    //定义标记,
    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();

    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值