内容:
在多线程的开发过程之中最为著名的案例就是生产者与消费者操作,该操作的主要流程如下:
· 生产者负责信息内容的生产;
· 每当生产者生产完成一项完整的信息之后消费者要从这里面取走信息;
· 如果生产者没有生产者则消费者要等待它生产完成,如果消费者还没有对信息进行消费,则生产者应该等待消费处理完成后再继续进行生产。
程序基本实现:
可以将生产者与消费者定义为两个独立的线程类对象,但是对于现在生产的数据,可以使用如下的组成:
数据1: name=面条、content=面粉;
数据2 name=火腿、content=猪肉;
既然生产者与消费者是两个独立的线程,那么这两个独立的线程之间就需要有一个数据的保存集中点,那么可以单独定义一个 (common) 类实现数据的保存。
package com.lyr.生产者消费者模型;
public class test {
public static void main(String[] args) {
Common com = new Common();
new Thread(new Producer(com)).start();
new Thread(new Consumer(com)).start();
}
}
class Producer implements Runnable{ // 生产者
private Common com ;
public Producer (Common com){
this.com = com ;
}
@Override
public void run() {
for(int i = 0; i < 50; i++){
if(i % 2 == 0) {
this.com.setName("面条");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.com.setMade("面粉");
}else {
this.com.setName("火腿");
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.com.setMade("猪肉");
}
}
}
}
class Consumer implements Runnable{ // 消费者
private Common com ;
public Consumer (Common com){
this.com = com ;
} @Override
public void run() {
for(int i = 0; i < 50; i++){
try {
Thread.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println(this.com.getName() + "$" + this.com.getMade());
}
}
}
class Common {
private String name ;
private String made ;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getMade() {
return made;
}
public void setMade(String made) {
this.made = made;
}
}
执行结果:
问题:
1:数据不同步了;
2:生产一个取走一个,但是发现有了重复生产和重复取出问题。
首先解决生产者和消费者的同步问题
如果要解决问题,首先解决的就是数据同步的处理问题,如果要想解决数据同步最简单的做法是使用 synchronized 关键字定义同步代码块或同步方法,于是这个时候对于同步的处理就可以直接在 (common) 类中完成。
class Common {
private String name ;
private String made ;
public synchronized void set(String name, String made){
this.name = name ;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.made = made ;
}
public synchronized String get(){
return this.name + "$" + this.made ;
}
}
执行结果:
在进行同步处理的时候肯定需要有一个同步的处理对象,那么此时肯定要将同步操作交由 (common) 类处理是最合适的。
这个时候发现数据已经可以正常的保持一致了,但是对于重复操作的问题依然存在。
利用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;
唤醒第一个等待线程: public final void notify();
唤醒全部等待线程: public final void notifyAll():
代码:
class Common {
private String name ;
private String made ;
private Boolean flag = true ;
//flag:TRUE 允许生产,但不允许消费
//flag:FALSE 允许消费,不允许生产
public synchronized void set(String name, String made){
if(this.flag == false){ // 如果有产品就无法进行生产,要等待消费
try {
super.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.name = name ;
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
this.made = made ;
this.flag = false ; // 表示已经生产了,要进行消费了
super.notify(); // 可能有等待的消费线程
}
public synchronized String get(){
if(this.flag == true){ // 还没有生产,需要等待执行
try {
super.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
try {
return this.name + "$" + this.made ;
}finally { // 不管怎样都要执行
this.flag = true ; // 只要消费了,就继续生产
super.notify(); // 唤醒等待的线程
}
}
}
执行结果:
自我学习笔记,希望对大家有帮助,点个赞,收藏一下!