1、程序的基本实现
多线程的开发过程之中著名案例就是生产者与消费者操作,该案例的主要流程如下:
1)生产者负责信息内容的生产;
2)当生产者完成一项完整的信息生产后,消费者则从这里取走信息;
3)如果生产者没有生产完一项信息,则消费者要等待它生产完成;如果消费者还没有对信息进行消费,则生产者应该等待消费处理完成之后再继续生产。
根据内容,可以将生产者和消费者定义为两个独立的线程类对象,两个独立的线程可以在单独定义的Message类中实现数据的保存(及使用Message类来建立联系点)。
程序基本模型:
范例:实现程序基本结构
代码 | 结果 |
package cn.demos; //生产者 private Message msg; public Producer(Message msg) { @Override } // 消费者 private Message msg; public Consumer(Message msg) { @Override } // 消费者信息 private String title; public String getTitle() { public void setTitle(String title) { public String getContent() { public void setContent(String content) { } public class Demo1 { | CSDN------null CSDN------null CSDN------null CSDN------null CSDN------null CSDN------null CSDN------null CSDN------null CSDN------null CSDN------一个实际操作平台 CSDN------一个实际操作平台 CSDN------一个实际操作平台 CSDN------一个实际操作平台 CSDN------一个实际操作平台 CSDN------一个实际操作平台 CSDN------一个实际操作平台 CSDN------一个实际操作平台 CSDN------一个实际操作平台 |
从以上程序中可以发现,CSDN的结果有null值,也有“一个实际操作平台”,而“一个实际操作平台”是程序中w3c的content值,所以从上面的程序中可以发现有两个主要问题:
1)数据不同步;
2)产生了重复生产和重复取出的问题。
2、解决生产者-消费者同步问题
解决数据同步最简单的做法是使用synchronized关键字定义同步代码块或者同步方法。所以此程序的同步处理可以在Message类中完成。
范例:解决同步操作
代码 | 结果 |
package cn.demos; //消费者信息 private String title; public synchronized void set(String title, String content) { public synchronized String get() { // 生产者 private Message msg; public Producer(Message msg) { @Override // 消费者 private Message msg; public Consumer(Message msg) { @Override System.out.println(this.msg.get()); } public class Demo1 { | w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 w3c-----一个实际操作平台 |
从上面程序中我们可以发现,title和content两个数据进行了绑定,解决了数据同步问题,但程序依然存在重复操作。
3、利用Object类解决重复操作
要解决生产者与消费者的问题,最好的解决方案是使用等待与唤醒机制,而等待与唤醒操作主要依靠的是Object类中提供的方法处理如下:
方法名 | 代码 | 描述 |
等待机制 | public final void wait() throws InterruptedException | 不设置时长,一直等待 |
public final void wait(long timeout) throws InterruptedException | 设置等待时长,超过等待时间就停止等待,继续执行 | |
public final void wait(long timeout, int nanos) throws InterruptedException | timeout -等待的最长时间(以毫秒为单位) nanos -附加时间,以纳秒为单位,范围为0-999999。 | |
唤醒机制 | public final void notify() | 多个线程,唤醒第一个等待线程,其他线程继续等待 |
public final void notifyAll() | 唤醒全部等待线程,按优先级顺序执行 |
而要解决本案例的问题,则需要先修改Message类
范例:修改Message类
代码 | 结果 |
package cn.demos; class Message { private String title; public synchronized void set(String title, String content) { this.title = title; public synchronized String get() { try { } // 生产者 private Message msg; public Producer(Message msg) { @Override // 消费者 private Message msg; public Consumer(Message msg) { @Override System.out.println(this.msg.get()); } public class Demo1 { | CSDN-----一个学习平台 w3c-----一个实际操作平台 CSDN-----一个学习平台 w3c-----一个实际操作平台 CSDN-----一个学习平台 w3c-----一个实际操作平台 CSDN-----一个学习平台 w3c-----一个实际操作平台 CSDN-----一个学习平台 w3c-----一个实际操作平台 CSDN-----一个学习平台 w3c-----一个实际操作平台 CSDN-----一个学习平台 w3c-----一个实际操作平台 CSDN-----一个学习平台 w3c-----一个实际操作平台 CSDN-----一个学习平台 |
修改了Message类中的代码后,此时我们可以发现程序运行结果是生产一个取走一个,已经达到了开始想要的效果。这种处理形式,就是多线程在进行开发之中最原始的处理方案,整个的等待、同步、唤醒机制都由开发者自行通过原生代码实现控制。