线程操作案例----生产者和消费者
既然现在的是信息,所以就可以定义一个信息的表示类,生产者和消费者都同时占有这个信息类的引用,那么,就可以将生产者和消费者两个线程通过信息类联合在一起。
建立生产者类,生产者实现多线程机制。生产者生产50此信息,中间为了更好的发现问题,加入了延迟操作。
实现消费者,消费者要不断的取出。
class Info{ // 定义信息类 private String name = "李兴华"; // 定义name属性 private String content = "JAVA讲师" ; // 定义content属性 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.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 ; } } } }; 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.printStackTrace() ; } System.out.println(this.info.getName() + " --> " + this.info.getContent()) ; } } }; public class ThreadCaseDemo01{ 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() ; } };
通过测试代码来发现程序的问题:
李兴华 --> www.mldnjava.cn 李兴华 --> www.mldnjava.cn 李兴华 --> www.mldnjava.cn mldn --> JAVA讲师 李兴华 --> www.mldnjava.cn 李兴华 --> JAVA讲师 mldn --> www.mldnjava.cn 李兴华 --> JAVA讲师 mldn --> JAVA讲师 mldn --> JAVA讲师 mldn --> www.mldnjava.cn 李兴华 --> JAVA讲师 mldn --> www.mldnjava.cn 李兴华 --> www.mldnjava.cn 李兴华 --> www.mldnjava.cn ......
之所以会出现内容不对应的情况,是因为中间加入了延迟操作,所以有可能产生不同步的问题,可以使用同步解决设置内容问题。
class Info{ // 定义信息类 private String name = "李兴华"; // 定义name属性 private String content = "JAVA讲师" ; // 定义content属性 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{ // 通过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 ThreadCaseDemo02{ 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() ; } };
mldn --> www.mldnjava.cn mldn --> www.mldnjava.cn 李兴华 --> JAVA讲师 李兴华 --> JAVA讲师 李兴华 --> JAVA讲师 mldn --> www.mldnjava.cn mldn --> www.mldnjava.cn mldn --> www.mldnjava.cn 李兴华 --> JAVA讲师 李兴华 --> JAVA讲师 mldn --> www.mldnjava.cn mldn --> www.mldnjava.cn mldn --> www.mldnjava.cn 李兴华 --> JAVA讲师 李兴华 --> JAVA讲师 ......
以上代码解决了数据的完整性问题,但依旧存在重复取的问题,既然有重复取,则肯定有重复设置的问题。
要达到设置一个取走一个的功能要求,如果想要采用以上的一种机制,则必须依靠Object类中的方法支持。
直接修改Info类即可增加等待与唤醒的机制
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() ; } };
李兴华 --> JAVA讲师 mldn --> www.mldnjava.cn 李兴华 --> JAVA讲师 mldn --> www.mldnjava.cn 李兴华 --> JAVA讲师 mldn --> www.mldnjava.cn 李兴华 --> JAVA讲师 mldn --> www.mldnjava.cn 李兴华 --> JAVA讲师 mldn --> www.mldnjava.cn 李兴华 --> JAVA讲师 mldn --> www.mldnjava.cn 李兴华 --> JAVA讲师 ......

浙公网安备 33010602011771号