请稍等 ...
×

采纳答案成功!

向帮助你的同学说点啥吧!感谢那些助人为乐的人

生产者-消费者模型的相关问题

翔哥,您好,我刚听完第八章 和第九章的第一节。尝试着,写了一下producer-and-consumer 代码。

有几个问题,网上找了一些资料。有几个点还不是特别理解,求指导。

先上代码

package com.imooc.thread;

import java.util.LinkedList;
import java.util.List;


/**
 * Single producer and consumer model 
 * @author tan3
 *
 */
public class ProducerAndConsumer {
	
	private static final List<Integer> BUFFER = new LinkedList<>();
	private static final Integer BUFFER_MAX_SIZE = 3;
	private static Integer productNum = 0;
	private static final Integer ITERATION = 10;
	
	public static void main(String[] args) {
		final Object lock = new Object();
		Thread producerThread = new Thread(new Runnable() {		
			@Override
			public void run() {
				// if the buffer is full, release the lock 
				synchronized(lock) {
					for(int idx =0; idx < ITERATION ;idx++) {
						if(BUFFER.size() == BUFFER_MAX_SIZE) {
							try {
								lock.wait();
							} catch (InterruptedException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						}
						// if the buffer is not full, produce one good and wake up the consumer
						try {
							System.out.println(Thread.currentThread().getName()
									   + " produce product: "+ productNum);
							Thread.sleep(1000);
							BUFFER.add(productNum++);
							lock.notifyAll();
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
					}
				}
				
			}
			
		},"Producer");
		
		Thread consumerThread = new Thread(new Runnable() {
			@Override
			public void run() {
				for(int idx =0; idx < ITERATION ;idx++) {
				// if the buffer is empty, release the lock and wake up the producer 
					synchronized(lock) {
						if(BUFFER.size() == 0) {
							try {
								lock.wait();
							} catch (InterruptedException e) {
								// TODO Auto-generated catch block
								e.printStackTrace();
							}
						}
						// if the buffer is not empty, produce one good and tell the consumer to produce one
						try {
							System.out.println(Thread.currentThread().getName()
									   + " consume product: "+ BUFFER.remove(0));
							Thread.sleep(1000);
							lock.notifyAll();
						} catch (InterruptedException e) {
							// TODO Auto-generated catch block
							e.printStackTrace();
						}
						
					}
				}
			}
			
		},"Consumer");
		
		producerThread.start();
		consumerThread.start();
		
		/*try {
			producerThread.join();
			consumerThread.join();
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		*/
	}

}

几个疑惑的点。

  1. 我这里用的是if(BUFFER.size() == BUFFER_MAX_SIZE) if语句进行判断的。网上说应该是用while 语句。 【在多线程中要测试某个条件的变化,使用if 还是while】 , 我测试了一下,我的程序跑了几遍。好像没出什么问题。(但是好像网上搜到的更多的是使用wait方法)。想知道这个地方到底该怎么理解。

  2. https://www.geeksforgeeks.org/producer-consumer-solution-using-threads-java/
    第二问题是关于join方法的。这个答案,最后用了join方法来确保生产线程 finishes before 消费者线程。(我试了一下,好像没什么用。)似乎这里不涉及抢占资源的问题吖?)

  3. 如果扩展multiple consumer and multiple producer,是不是BUFFER改成violate。以及voilate 是不是不可以跟final 并用。这里是用final 还是voilate。 怎么保证线程安全。我觉得final 就是保证线程安全比较好的方式了。。

可能概念有点多。学得越多越糊涂了。希望和大家探讨。

正在回答

2回答

同学好,我一个个问题回答哈

  1. 现在只有一个生产者,使用if是没问题的,如果存在多个生产者的话,是会多生产的,此时需要使用while,因为调用wait之后被唤醒是会接着执行的。

  2. 代码里其实已经决定哪个线程先执行完了,所以不需要join方法。

  3. 使用final是不能保证安全的,多个生产者或消费者的话,每次也只有一个能获取到对象锁,直接用现在这种写法就可以,无非就是多起几个线程。


1 回复 有任何疑惑可以回复我~
  • 提问者 慕斯6088333 #1
    好的。知道了,我昨天又尝试着手动写了一遍代码试了一下。感觉没错了。是从wait方法后面开始执行的。当多个生产者的话是需要double -check一下的,来保证buffer不溢出或为空。2. 那join方法经典的应用场景是哪些吖。能否给一个经典的例子吖。3. 我看了看相关资料,有些理解了,用final就好保证对象地址不变即可。synchronized已经保证了。
    回复 有任何疑惑可以回复我~ 2019-04-10 00:43:03
  • 翔仔 回复 提问者 慕斯6088333 #2
    join方法的话,在某些情况下,主线程创建并启动了子线程,如果子线程中需要进行大量的耗时运算,主线程往往将早于子线程结束之前结束,如果主线程想等待子线程执行完毕后,获得子线程中的处理完的某个数据,就要用到join方法了
    回复 有任何疑惑可以回复我~ 2019-04-10 01:08:23
  • 提问者 慕斯6088333 回复 翔仔 #3
    好的。了解了。
    回复 有任何疑惑可以回复我~ 2019-04-10 01:13:53
提问者 慕斯6088333 2019-04-10 00:50:44

我发现翔哥,你公开课讲的deadlock demo 。我尝试着加了语句,解开dead lock 。我以为先后顺序是用join方法控制,确保线程1把锁释放,让线程2拿到锁,然后让线程2执行完,结束生命周期前唤醒线程1,然后线程1自然而然有了b的锁。。到底是线程1还是2先执行完取决于谁调用wait方法和执行前后顺序有关。那么join到底啥时候用啊

package com.imooc.thread;

public class DeadLockDemo {
	
	public static void main(String[] args) {
		final Object lockA = new Object();
		final Object lockB = new Object();
		
		Thread t1 = new Thread( new Runnable() {
			@Override
			public void run() {
				// TODO Auto-generated method stub
				String name = Thread.currentThread().getName();
				synchronized(lockA) {
					System.out.println(name +" got lock A, waiting to get lock B");
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					try {
						lockA.wait();
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					synchronized(lockB) {
						System.out.println(name +" got lock B");
						System.out.println(name+"finish");
					}
				}
				
			}
			
		},"Thread A");
		
		Thread t2 = new Thread( new Runnable() {
			@Override
			public void run() {
				// TODO Auto-generated method stub
				String name = Thread.currentThread().getName();
				synchronized(lockB) {
					System.out.println(name +" got lock B, waiting to get lock A");
					try {
						Thread.sleep(1000);
					} catch (InterruptedException e) {
						// TODO Auto-generated catch block
						e.printStackTrace();
					}
					synchronized(lockA) {
						System.out.println(name +" got lock A");
						System.out.println(name+"finish");
						lockA.notifyAll();
					}
				}
				
			}
			
		},"Thread B");
		t1.start();
		/*try {
			Thread.sleep(5000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}*/
		t2.start();	
		
		
	}
}


0 回复 有任何疑惑可以回复我~
  • 翔仔 #1
    同学好,这个场景的话,不需要使用锁,用join就能完成,比如在线程B中调用了线程A的Join()方法,直到线程A执行完毕后,才会继续执行线程B。
    回复 有任何疑惑可以回复我~ 2019-04-10 20:42:59
  • 提问者 慕斯6088333 回复 翔仔 #2
    卧槽。这么一说那还真的是这样。。会更容易理解一些。。
    回复 有任何疑惑可以回复我~ 2019-04-10 23:06:16
问题已解决,确定采纳
还有疑问,暂不采纳
意见反馈 帮助中心 APP下载
官方微信