生产者和消费者问题

生产者和消费者问题是一个著名的进程同步问题
什么是进程同步?
多个进程在执行的时候,它们要按照一定的规则共享系统资源,这种进程间的相互制约关系就是进程同步机制。

问题描述
生产者进程:生产产品
消费者进程:消费产品
两者之间设置了个缓冲池(含有n个缓冲区)
生产者生产完,把产品放进一个缓冲区里,消费者消费,就从一个缓冲区中取走产品
两个进程必须同步:不允许消费者进程从一个空缓冲区中取产品,也不允许生产者进程向一个已经满了的缓冲区投放产品

分析
我们定义一些变量:
缓冲池:buffer[n]
投入一个产品:数组单元指针in加1,表示成in=(in+1)%n,含义是暂存产品数量加1
取走一个产品:数组单元指针out加1,表示成out=(out+1)%n,含义是空闲单元数量加1
对n取余是因为缓冲池里的缓冲区是循环组成的。
变量counter:投放产品:counter+1,取走产品:counter-1

初始化
int in=0,out=0,counter=0;
item buffer[n]
以上变量生产者进程和消费者进程共有

用生产者进程的局部变量nextp暂时存放刚刚生产出来的产品。
用消费者进程的局部变量nextc暂时存放每次要消费的产品。

void producer(){
	while(1){
		produce an item in nextp;
		...
		while(counter==n)
		;
		buffer[in]=nextp;
		in=(in+1)%n;
		counter++;
	}
};
void consumer(){
	while(1){
		while(counter==0)
		;
		nextc=buffer[out];
		out=(out+1)%n;
		counter--;
		consume the item in nextc;
		...
	}
};

但是这两个程序在并发执行会出现错误,问题在于这两个进程共享变量counter
counter的加1和减1操作我们这样描述:
register1=counter; register2=counter;
register1=register1+1; register2=register2-1;
counter=register1; counter=register2;
这六个语句的执行顺序如果发生改变,得到的最后的counter的值可能不同。
解决:把变量counter作为临界资源,生产者进程和消费者进程互斥地访问 counter

用java写个生产者和消费者模型

实际上需要一个缓冲区,但是本例只设了一个共享整数

package thread_test;

//消费者
class Consumer extends Thread {
	private ShareArea sharedObject;
	
	public Consumer(ShareArea shared) {
		sharedObject = shared;
	}
	
	public void run() {
		int value;
		do {
			try {
				Thread.sleep((int)(Math.random()*3000));
			}catch(InterruptedException exception){}
			value = sharedObject.getSharedInt();	//获取共享整数的值
			System.out.println("消费:"+ value);
		}while(value != 10);
	}
}

//生产者
class Producer extends Thread {
	private ShareArea sharedObject;
	
	public Producer(ShareArea shared) {
		sharedObject = shared;
	}
	
	public void run() {
		for(int cnt = 1;cnt <=10 ;cnt++) {
			try {
				Thread.sleep((int)(Math.random()*2000));
			}catch(InterruptedException exception){}
			sharedObject.setSharedInt(cnt);//更改共享数据
			System.out.println("生产:" + cnt);
		}
	}
}

//共享数据访问程序
class ShareArea {
	private int sharedInt = -1;		//共享整数
	private boolean writable = true;//条件变量
	
	public synchronized void setSharedInt(int value) {
		while(! writable) {
			try {
				wait();				//轮不到生产者写就等待
			}catch(InterruptedException exception) {}
		}
		sharedInt = value;			//生产者写入一个值
		writable = false;           //消费者操作前,生产者不能写入另一个值
		notify();					//唤醒等待资源的线程
	}
	
	public synchronized int getSharedInt() {
		while(writable) {
			try {
				wait();				//没轮到消费者就等待
			}catch(InterruptedException exception) {}
		}
		writable = true;			//生产者要等生产者再生产才能消费另一个值
		notify();					//唤醒等待资源的线程
		return sharedInt;			//消费者得到数据
	}
}

public class SharedTest {
	public static void main(String args[]) {
		ShareArea shareObject = new ShareArea();
		Producer p =new Producer(shareObject);
		Consumer c =new Consumer(shareObject);
		p.start();c.start();
	}	
}

上面提到的synchronized关键字是一种
java中,谈到线程安全问题,常见操作就是加锁来实现资源共享,一般来说主要有synchronize和Lock两种锁
一、锁的概念
当有多个线程想要访问一临界资源的时候,就会出现冲突,而锁就是解决这种冲突的。和上厕所一样,假如有ABC三个人都来上厕所,A先来了,那么在A出来之前,这个厕所就处在了“锁”定状态,B和C憋死也要在外面等着。
二、synchronized关键字的使用

  1. 修饰代码块,锁的是当前代码块
public  void show() {
        Object o=new Object();
        synchronized (o) {
            System.out.println("Synchronized修饰的代码块!");
        }
    }
  1. 修饰一般方法,锁的是实例对象
public synchronized void show() {
        System.out.println("Synchronized修饰的一般方法!");
    }
    public static void main(String[] args) {
        Test test=new Test();
        test.show();
    }
  1. 修饰静态方法,锁的是类对象
public static synchronized void show() {
        System.out.println("Synchronized修饰的静态方法!");
    }

wait():释放占有的对象锁,释放CPU
notify():唤醒等待队列中的一个线程,使其获得锁进行访问

  • 2
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

漂流の少年

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值