Java多线程13 妖的出现

需求:

资源有姓名和性别

两个线程

一个负责赋值/一个负责获取姓名和性别

要求1.运行代码,解决“妖”的问题

分析过程:典型的多线程安全问题

解决办法:加入同步,必须保证是同一个锁,解决妖的问题

要求二:实现数据的间隔输出

要求三:对代码进行重构。将name  sex 私有化,资源类对外提供方法

要求四:将程序改为 Lock  Condition   接口

代码:

package Thread;//妖的出现
//初始代码
//描述资源
class Resources{
    String name;
    String sex;
}
//线程任务————赋值
class Input implements Runnable{
    private Resources r;
    Input(Resources r){//线程任务一初始化就必须要有处理的资源
        this.r=r;
    }
    public void run(){
        int x = 0;
        for(int y=0;y<5;y++){
            if(x==0){
                r.name ="Lizhuzhu";
                r.sex = "男";
            }
            else{
                r.name = "rose";
                r.sex = "女";
            }
            x=(x+1)%2;//实现切换
        }
    }
}
//线程任务————获取
class Output implements Runnable{
    private Resources r;
    Output(Resources r){
        this.r= r;
    }
    public void run(){
        for(int y=0;y<5;y++){
            System.out.println(r.name+"......"+r.sex);
        }
    }
}
public class YaoProblem {
    public static void main(String[] args){
        Resources r = new Resources();
        Input in = new Input(r);
        Output out = new Output(r);
        Thread t1 = new Thread(in);
        Thread t2 = new Thread(out);
        t1.start();
        t2.start();
    }
}

乍一看代码没有问题,但是实际运行结果就会出现数据错误

错误一:Lizhuzhu ..........女女

rose.............男

rose.............女女

rose.............女女

乍一看以为是多线程的安全问题(用同步解决)———直接在每个类中创建obj作为锁但是这sh

是不行的,当你在每个类中创建obj 的时候其实,你创建了两个不一样的obj 两个不一样的锁

程安全问题的前提1.有共享数据     2有多条语句操纵共享数据    3.也是最为重要的时,有多个线程共用同一个锁,多个线程共用一个锁才存在锁起来的问题。

因此要保证两个线程任务的锁是一样的:1.使用资源的对象(资源对象是唯一的)。2.使用类文件的class 文件,这个在内存中其实也是一个对象,而且是唯一

修改后的代码:

package Thread;//妖的出现
//初始代码
//描述资源
class Resources{
    String name;
    String sex;
}
//线程任务————赋值
class Input implements Runnable{
    private Resources r;
    Input(Resources r){//线程任务一初始化就必须要有处理的资源
        this.r=r;
    }
    public void run(){
        int x = 0;
        for(int y=0;y<10;y++){
            synchronized (r) {
                if (x == 0) {
                    r.name = "Lizhuzhu";
                    r.sex = "男";
                } else {
                    r.name = "rose";
                    r.sex = "女女";
                }
            }
                x = (x + 1) % 2;//实现切换
        }
    }
}
//线程任务————获取
class Output implements Runnable{
    private Resources r;
    Output(Resources r){
        this.r= r;
    }
    public void run(){
        for(int y=0;y<10;y++){
            synchronized (r) {
                System.out.println(r.name + "......" + r.sex);
            }
        }
    }
}
public class YaoProblem {
    public static void main(String[] args){
        Resources r = new Resources();
        Input in = new Input(r);
        Output out = new Output(r);
        Thread t1 = new Thread(in);
        Thread t2 = new Thread(out);
        t1.start();
        t2.start();
    }
}

但是这样修改后运行任然存在问题:数据结果呈现出只有一种结果(要么只有Lizhuzhu    男/要么只有rose    女女)

出现这种错误的原因:输出线程长时期的拥有CPU的执行权

问题:如何实现间隔输出:Lizhuzhu       男     rose         女女    Lizhuzhu     男     rose    女女

解决办法:使用等待唤醒机制————要设置标识

代码:

package Thread;//妖的出现
//初始代码
//描述资源
class Resources{
    String name;
    String sex;
    boolean flag;
}
//线程任务————赋值
class Input implements Runnable{
    private Resources r;

    Input(Resources r){//线程任务一初始化就必须要有处理的资源
        this.r=r;
    }
    public void run(){
        int x = 0;
        for(int y=0;y<10;y++) {
            synchronized (r) {
                if (r.flag) {
                    try {
                        r.wait();
                    } catch (InterruptedException e) {
                    }

                }
                if (x == 0) {
                    r.name = "Lizhuzhu";
                    r.sex = "男";
                } else {
                    r.name = "rose";
                    r.sex = "女女";
                }
                r.flag=true;
                r.notify();
            }
            x = (x + 1) % 2;//实现切换 }
        }
    }
}
//线程任务————获取
class Output implements Runnable{
    private Resources r;
    Output(Resources r){
        this.r= r;
    }
    public void run(){
        for(int y=0;y<10;y++){
            synchronized (r) {
                if(!r.flag){
                    try {
                        r.wait();
                    } catch (InterruptedException e) {
                    }
                }
                System.out.println(r.name + "......" + r.sex);
                r.flag=false;
                r.notify();
            }
        }
    }
}
public class YaoProblem {
    public static void main(String[] args){
        Resources r = new Resources();
        Input in = new Input(r);
        Output out = new Output(r);
        Thread t1 = new Thread(in);
        Thread t2 = new Thread(out);
        t1.start();
        t2.start();
    }
}

注意代码细节!!!

对代码进行重构:

class Resources{
    private String name;
    private String sex;
    boolean flag=false;
    public synchronized void Input(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 Output(){
        if(!flag){
        try {
            this.wait();
        } catch (InterruptedException e) {
        }
    }
        System.out.println(name + "......" +sex);
        flag=false;
        this.notify();
    }
}
class Input implements Runnable{
    private Resources r;
    Input(Resources r){
        this.r=r;
    }
    public void run(){
        int x=0;
        for(int y=0;y<5;y++){
            if(x==0){
                r.Input("Lizhuzhu","男");
            }
            else{
                r.Input("rose","女女");
            }
            x=(x+1)%2;
        }
    }
}
class Output implements Runnable{
    private Resources r;
    Output(Resources r){
        this.r=r;
    }
    public void run(){
      for(int y=0;y<5;y++) {
          r.Output();
      }
    }
}
public class YaoProblem {
    public static void main(String[] args){
        Resources r = new Resources();
        Input in = new Input(r);
        Output out = new Output(r);
        Thread t1 = new Thread(in);
        Thread t2 = new Thread(out);
        t1.start();
        t2.start();
    }
}

需求四:使用Lock接口

代码:

class Resources{
    private String name;
    private String sex;
    boolean flag=false;
    private Lock lock = new ReentrantLock();
    private Condition con = lock.newCondition();

    public  void Input(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 Output(){
        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 Resources r;
    Input(Resources r){
        this.r=r;
    }
    public void run(){
        int x=0;
        for(int y=0;y<5;y++){
            if(x==0){
                r.Input("Lizhuzhu","男");
            }
            else{
                r.Input("rose","女女");
            }
            x=(x+1)%2;
        }
    }
}
class Output implements Runnable{
    private Resources r;
    Output(Resources r){
        this.r=r;
    }
    public void run(){
      for(int y=0;y<5;y++) {
          r.Output();
      }
    }
}
public class YaoProblem {
    public static void main(String[] args){
        Resources r = new Resources();
        Input in = new Input(r);
        Output out = new Output(r);
        Thread t1 = new Thread(in);
        Thread t2 = new Thread(out);
        t1.start();
        t2.start();
    }
}

猜你喜欢

转载自blog.csdn.net/Stitch__/article/details/81909913