【多线程】_线程操作案例——生产者和消费者笔记

来源:互联网 发布:深圳市软件产业基地4栋 编辑:程序博客网 时间:2024/06/05 08:49
实例要求:在线程操作中有一个经典的案例程序——生产者和消费者问题,生产者不断生产,消费者不断取走生产者生产的产品。

既然是信息,所以就可以定义一个信息的表示类,生产者和消费者都同时占有这个信息类的引用,那么就可以将生产者和消费者两个线程通过信息类联合在一起。

class Info{//定义信息类    private String name = "牛儿吃草";    private String content = "Java 讲师";        public void setName(String name){        this.name = name;    }    public void setContent(String content){        this.content = content;    }    public String getName(){        return this.name;    }    public String getContent(){        return this.content;    }}//建立生产者类,生产者实现多线程机制class Producer implements Runnable{    private Info info = null;    public Producer(Info info){        this.info = info;    }    public void run(){        boolean flag = false;        for(int i=0;i<50;i++){            if(flag){                this.info.setName("李兴华");                try{                    Thread.sleep(90);                }catch(InterruptedException e){                    e.printStackTrace();                }                this.info.setContent("JAVA讲师");                flag = false;            }else{                this.info.setName("mldn");                try{                    Thread.sleep(90);                }catch(InterruptedException e){                    e.printStackTrace();                }                this.info.setContent("www.mldnjava.cn");//设置内容                flag = true;            }                }        }}//生产者生产50次信息,中间为了更好的发现问题,加入了延迟操作。//实现消费者,消费者要不断的取出。class Consumer implements Runnable{    private Info info = null;    public Consumer(Info info){        this.info = info;    }    public void run(){        for(int i=0;i<50;i++){            try{                Thread.sleep(90);            }catch(InterruptedException e){                e.printStackTrack();            }            System.out.println(this.info.getName()+                "-->"+this.info.getContent()            );        }        }}//通过测试代码来发现程序的问题:public class ThreadCaseDemo01{    public static void main(String args[]){        Info info = new Info();        Producer pro = new Producer(info);    //生产者        Consumer con = new Consumer(info);        new Thread(pro).start();        new Thread(con).start();    }}



mldn-->JAVA讲师
mldn-->JAVA讲师
mldn-->JAVA讲师
mldn-->JAVA讲师
mldn-->JAVA讲师
李兴华-->www.mldnjava.cn
李兴华-->www.mldnjava.cn
李兴华-->www.mldnjava.cn
李兴华-->www.mldnjava.cn
mldn-->JAVA讲师
mldn-->JAVA讲师
李兴华-->www.mldnjava.cn


以上的代码将之前的两个问题全部暴露出来了。

之所以会出现内容不对应的情况,是因为中间加入了延迟操作,所以有可能产生不同步的问题,那么此时,可以使用同步解决设置内容的问题。

class Info{//定义信息类    private String name = "牛儿吃草";    private String content = "Java 讲师";            public synchronized void set(String name,String content){        this.setName(name);    //设置名称        try{            Thread.sleep(300);        }catch(InterruptedException e){            e.printStackTrace();        }        this.setContent(content);    }    public synchronized void get(){        try{            Thread.sleep(300);        }catch(InterruptedException e){            e.printStackTrace();        }        System.out.println(this.getName()+"-->"+this.getContent());    }    public void setName(String name){        this.name = name;    }    public void setContent(String content){        this.content = content;    }    public String getName(){        return this.name;    }    public String getContent(){        return this.content;    }}class Producer implements Runnable{    private Info info = null;    public Producer(Info info){        this.info = info;    }    public void run(){        boolean flag = false;        for(int i=0;i<50;i++){            if(flag){                this.info.set("李兴华","JAVA讲师");                flag = false;            }else{                this.info.set("mldn","www.mldnjava.cn");                flag = true;            }        }    }}class Consumer implements Runnable{    private Info info = null;    public Consumer(Info info){        this.info = info;    }    public void run(){        for(int i=0;i<50;i++){            this.info.get();        }        }}public class ThreadCaseDemo02{    public static void main(String args[]){        Info info = new Info();        Producer pro = new Producer(info);        Consumer con = new Consumer(info);        new Thread(pro).start();        new Thread(con).start();    }}



牛儿吃草-->JAVA讲师
牛儿吃草-->JAVA讲师
牛儿吃草-->JAVA讲师
牛儿吃草-->JAVA讲师
牛儿吃草-->JAVA讲师
牛儿吃草-->JAVA讲师
牛儿吃草-->JAVA讲师
牛儿吃草-->JAVA讲师
牛儿吃草-->JAVA讲师
牛儿吃草-->JAVA讲师
牛儿吃草-->JAVA讲师
牛儿吃草-->JAVA讲师
牛儿吃草-->JAVA讲师
牛儿吃草-->JAVA讲师
mldn-->www.mldnjava.cn
mldn-->www.mldnjava.cn

以上的代码解决了数据完整性问题,但是依然存在了重复取的问题,既然有重复取,则肯定有重复设置问题。
并没有达到,设置一个取走一个的功能要求。

如果要想采用以上的一种机制,则必须依靠Object 类中的方法支持。

Object类对线程的支持——等待与唤醒

Object 类是所有类的父类,在此类中有以下几个方法是对线程操作有所支持的。

唤醒现有两个方法:notify,notifyAll

notify()方法唤醒第一个等待的线程执行
notifyAll()方法唤醒所有的等待线程执行

class Info{    // 定义信息类    private String name = "李兴华";     // 定义name属性    private String content = "JAVA讲师"  ;        // 定义content属性    private boolean flag = false ;    // 设置标志位    public synchronized void set(String name,String content){        if(!flag){            try{                super.wait() ;            }catch(InterruptedException e){                e.printStackTrace() ;            }        }        this.setName(name) ;    // 设置名称        try{            Thread.sleep(300) ;        }catch(InterruptedException e){            e.printStackTrace() ;        }        this.setContent(content) ;    // 设置内容        flag  = false ;    // 改变标志位,表示可以取走        super.notify() ;    }    public synchronized void get(){        if(flag){            try{                super.wait() ;            }catch(InterruptedException e){                e.printStackTrace() ;            }        }        try{            Thread.sleep(300) ;        }catch(InterruptedException e){            e.printStackTrace() ;        }        System.out.println(this.getName() +            " --> " + this.getContent()) ;        flag  = true ;    // 改变标志位,表示可以生产        super.notify() ;    }    public void setName(String name){        this.name = name ;    }    public void setContent(String content){        this.content = content ;    }    public String getName(){        return this.name ;    }    public String getContent(){        return this.content ;    }};class Producer implements Runnable{    // 通过Runnable实现多线程    private Info info = null ;        // 保存Info引用    public Producer(Info info){        this.info = info ;    }    public void run(){        boolean flag = false ;    // 定义标记位        for(int i=0;i<50;i++){            if(flag){                this.info.set("李兴华","JAVA讲师") ;    // 设置名称                flag = false ;            }else{                this.info.set("mldn","www.mldnjava.cn") ;    // 设置名称                flag = true ;            }        }    }};class Consumer implements Runnable{    private Info info = null ;    public Consumer(Info info){        this.info = info ;    }    public void run(){        for(int i=0;i<50;i++){            this.info.get() ;        }    }};public class ThreadCaseDemo03{    public static void main(String args[]){        Info info = new Info();    // 实例化Info对象        Producer pro = new Producer(info) ;    // 生产者        Consumer con = new Consumer(info) ;    // 消费者        new Thread(pro).start() ;        new Thread(con).start() ;    }};