您好,登录后才能下订单哦!
这篇文章将为大家详细讲解有关Java多线程中消费者与生产者的关系是什么,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。
多线程:CPU中各种任务在交替执行过程中,被称为多线程处理。其中,每个任务的一次动态执行过程被称为进程。进程执行过程中的暂停被称为中断。进程通过中断被分解成若干段,每一段被称为一个线程。
在消费者与生产者中,我们设定单个生产者的每次活动是馒头 +1;单个消费者每次进行的是馒头 -1;然后消费者和生产者的活动时间不确定,同时生产者和消费者的数量不确定,该经典问题我们使用多线程实现:
我们首先确定实物,即生产者的每次生成的物品,在这里我们使用馒头代替。在WoTou的类中,我们可以看到有着自己独特的属性,即馒头的 id,我们可以在控制台清晰的看到馒头的生产和消费过程,具体实现代码如下:
class WoTou{ //馒头,生产者生产的馒头
int id;
WoTou(int id){
this.id = id;
}
public String toString(){
return "WoTou:"+ id;
}
}
我们需要确定馒头的存储容器,即在消费和生产发生的时候,我们需要在什么地方进行判断,馒头是否耗尽,或者馒头是否满溢。每次活动都是相当于在栈中取东西和放东西,所以我们根据栈的特性为:先进后出 原则。
class SyncStack {//篮子容器,放馒头用的
int index = 0;
WoTou[] arrWT = new WoTou[6];
}
在篮子容器中我们简单定义栈的最大容量为6,我们之后设定生产者的类,定义为producer类。我们知道producer有着一些自己的独特属性,即往篮子SyncStack中放WoTou,每次进行馒头+1操作,还有生产者的操作Time间隔,是隔10毫秒还是5毫秒,我们使得producer类实现其Runnerable接口,调用线程的run()方法,具体代码如下:
class Producer implements Runnable{ //生产者
SyncStack ss= null;
Producer(SyncStack ss){
this.ss = ss;
}
public void run(){
for(int i=0;i<20;i++){
WoTou wt = new WoTou(i);
ss.push(wt);
System.out.println("生产者:"+wt);
try {
Thread.sleep((int)(Math.random()*1000));
} catch (InterruptedException e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
}
生产者在往栈中添加数据的时候,我们使用push方法进行插入。同时定义插入的馒头数量,这里的数量并不是篮子的馒头数量。篮子里边虽然只能一次性装6个馒头,但是消费者是同时间进行操作的,所以篮子的馒头数量在消费之后,生产者继续进行生产,一直到生产20个馒头为止。
消费者我们这里定义为Consumer类,消费者和生产者有一定的相似性,但是我们需要消费在篮子中拿的过程,我们使用pop操作,同时定义消费数量,以及操作间隔,这里都是使用线程的sleep(时间)方法, 代码如下:
class Consumer implements Runnable{ //消费者
SyncStack ss= null;
Consumer(SyncStack ss){
this.ss = ss;
}
public void run(){
for(int i=0;i<20;i++){
WoTou wt = ss.pop();
System.out.println("消费量:"+wt);
try {
Thread.sleep((int)(Math.random()*1000));
} catch (InterruptedException e) {
// TODO: handle exception
e.printStackTrace();
}
}
}
}
最后我们考虑在篮子中,假如容量已满,即生产者生产过多,消费的太慢,那么生产者需要休息;同样的消费过快,容器数量为0,消费者开始休息。我们在两种情况发生的时候,需要设置两种方法,在极限情况发生的时候,进行判断。简单实现代码如下:
public synchronized void push(WoTou wt){ //往篮子中放馒头
while(index == arrWT.length){
try {
this.wait();
} catch (InterruptedException e) {
// TODO: handle exception
e.printStackTrace();
}
}
this.notify();
arrWT[index] = wt;
index++;
}郑州人流多少钱 http://mobile.sgyy029.com/
我们需要确定是我们在生产者进行活动的时候,不能受到其他线程的影响,即我们需要保持在某一时刻只有一个线程进行操作,这种情况我们需要使用线程的一个synchronized方法。这个方法称为死锁,锁定当前方法体执行的过程中,保持其独立性。即在方法体的前面使用synchronized关键字修饰。
从篮子中取出馒头的操作类似于生产者,实现代码如下:
public synchronized WoTou pop(){ //从篮子中取馒头
while(index == 0){
try {
this.wait();
} catch (InterruptedException e) {
// TODO: handle exception
e.printStackTrace();
}
}
this.notify();
index--;
return arrWT[index];
}
我们会发现在上面两种动作中,考虑到一个问题,即数量到极限之后,我们的动作停止了。生产者在篮子容量到达6时,动作停止;消费者在篮子数量到0后,停止行为。我们这时候开始使用线程的notify方法,唤醒休眠的线程,因为线程使用了wait方法,我们可以唤醒之后,在进行各自的行为。因此篮子SynStack类中详细代码为:
class SyncStack {//篮子容器,放馒头用的
int index = 0;
WoTou[] arrWT = new WoTou[6];
public synchronized void push(WoTou wt){ //往篮子中放馒头
while(index == arrWT.length){
try {
this.wait(); //线程等待
} catch (InterruptedException e) {
// TODO: handle exception
e.printStackTrace();
}
}
this.notify(); //唤醒wait的线程
arrWT[index] = wt;
index++;
}
public synchronized WoTou pop(){ //从篮子中取馒头
while(index == 0){
try {
this.wait();
} catch (InterruptedException e) {
// TODO: handle exception
e.printStackTrace();
}
}
this.notify();
index--;
return arrWT[index];
}
}
我们可以修改生产者和消费者的数量和操作间隔,不一定生产+1同时消费-1。我们可以根据修改进行更改代码,上面的运行在控制台数据
关于“Java多线程中消费者与生产者的关系是什么”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。