刚学java的多线程写了一个生产者消费者的小例子,但是不太确定有没有问题,哪位高手看看有问题或可以改进的地方请指出来,不胜感激!!!!
package thread;import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;public class CustomerProducterThread { public static void main(String[] args) {
Storage storage = new Storage();
Customer c1 = new Customer(storage);
c1.setName("c1");
Customer c2 = new Customer(storage);
c2.setName("c2");
Customer c3 = new Customer(storage);
c3.setName("c3");
Customer c4 = new Customer(storage);
c4.setName("c4");
Producter p1 = new Producter(storage);
p1.setName("p1");
Producter p2 = new Producter(storage);
p2.setName("p2");
Producter p3 = new Producter(storage);
p3.setName("p3");
Producter p4 = new Producter(storage);
p4.setName("p4");
c1.start();
c2.start();
p1.start();
p2.start();
p3.start();
p4.start();
c3.start();
c4.start(); }
}class Storage {//仓库 public static final int[] lock = new int[0];
public static final Integer max = 100;
private Integer sto = 0; public void put(int i, String name) {//生产者放
synchronized (lock) {
if ((this.sto + i) > max) {
System.out.println(name + "仓库已满............" + i);
try {
lock.wait();
put(i,name);//等wait结束后继续调用put方法来放置刚才生产的i个产品
} catch (InterruptedException ex) {
Logger.getLogger(Storage.class.getName()).log(Level.SEVERE, null, ex);
}
} else {
this.sto = this.sto + i;
System.out.println(name + "生产了" + i + "个产品,现在库存量" + this.sto);
lock.notifyAll();
}
}
} public void get(int i, String name) {//消费者取
synchronized (lock) {
if (this.sto - i < 0) {
System.out.println(name + "仓库余额不足............" + i);
try {
lock.wait();
get(i,name);
} catch (InterruptedException ex) {
Logger.getLogger(Storage.class.getName()).log(Level.SEVERE, null, ex);
}
} else {
this.sto = this.sto - i;
System.out.println(name + "消费了" + i + "个产品,现在库存量" + this.sto);
lock.notifyAll();
}
}
}
}class Customer extends Thread {//消费者 public Storage sto; public Customer(Storage sto) {
this.sto = sto;
} @Override
public void run() {
while (true) {
sto.get(new Random().nextInt(10) + 1, Thread.currentThread().getName());
} }
}class Producter extends Thread {//生产者 public Storage sto; public Producter(Storage sto) {
this.sto = sto;
} @Override
public void run() {
while (true) {
sto.put(new Random().nextInt(10) + 1, Thread.currentThread().getName());
} }
}
package thread;import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;public class CustomerProducterThread { public static void main(String[] args) {
Storage storage = new Storage();
Customer c1 = new Customer(storage);
c1.setName("c1");
Customer c2 = new Customer(storage);
c2.setName("c2");
Customer c3 = new Customer(storage);
c3.setName("c3");
Customer c4 = new Customer(storage);
c4.setName("c4");
Producter p1 = new Producter(storage);
p1.setName("p1");
Producter p2 = new Producter(storage);
p2.setName("p2");
Producter p3 = new Producter(storage);
p3.setName("p3");
Producter p4 = new Producter(storage);
p4.setName("p4");
c1.start();
c2.start();
p1.start();
p2.start();
p3.start();
p4.start();
c3.start();
c4.start(); }
}class Storage {//仓库 public static final int[] lock = new int[0];
public static final Integer max = 100;
private Integer sto = 0; public void put(int i, String name) {//生产者放
synchronized (lock) {
if ((this.sto + i) > max) {
System.out.println(name + "仓库已满............" + i);
try {
lock.wait();
put(i,name);//等wait结束后继续调用put方法来放置刚才生产的i个产品
} catch (InterruptedException ex) {
Logger.getLogger(Storage.class.getName()).log(Level.SEVERE, null, ex);
}
} else {
this.sto = this.sto + i;
System.out.println(name + "生产了" + i + "个产品,现在库存量" + this.sto);
lock.notifyAll();
}
}
} public void get(int i, String name) {//消费者取
synchronized (lock) {
if (this.sto - i < 0) {
System.out.println(name + "仓库余额不足............" + i);
try {
lock.wait();
get(i,name);
} catch (InterruptedException ex) {
Logger.getLogger(Storage.class.getName()).log(Level.SEVERE, null, ex);
}
} else {
this.sto = this.sto - i;
System.out.println(name + "消费了" + i + "个产品,现在库存量" + this.sto);
lock.notifyAll();
}
}
}
}class Customer extends Thread {//消费者 public Storage sto; public Customer(Storage sto) {
this.sto = sto;
} @Override
public void run() {
while (true) {
sto.get(new Random().nextInt(10) + 1, Thread.currentThread().getName());
} }
}class Producter extends Thread {//生产者 public Storage sto; public Producter(Storage sto) {
this.sto = sto;
} @Override
public void run() {
while (true) {
sto.put(new Random().nextInt(10) + 1, Thread.currentThread().getName());
} }
}
解决方案 »
- Java应用程序如何生成EXE文件,可以再电脑上面没有JDK的情况下正常运行
- 不显示删除回复显示所有回复显示星级回复显示得分回复 跪求《Thinking in Java》教材的课后习题答案(附加小问题的)(一个大一菜鸟的发问)
- 怎样将文本框中的字符串转化为float型??
- getFileName() 找不到?谢谢帮忙
- 请问高手解释什么是字节码校验器,类加载器
- 我的数据库是access的叫alb,这么连接多吗?
- 请教一个字符串的问题?
- 我有道题初级的
- JDK1.3 中的java命令不好用?
- 毕业设计做JAVA,怎么写文档啊
- 多个socket的多线程问题
- w3c element getLocalName为null?
put(i,name);//递归调用,有什么特别意义吗?多余的处理,把else去掉就可以了,wait结束后,直接执行else部分的代码,即
synchronized (lock) {
if ((this.sto + i) > max) {
System.out.println(name + "仓库已满............" + i);
try {
lock.wait();
//put(i,name);//等wait结束后继续调用put方法来放置刚才生产的i个产品
} catch (InterruptedException ex) {
Logger.getLogger(Storage.class.getName()).log(Level.SEVERE, null, ex);
}
} //else {
this.sto = this.sto + i;
System.out.println(name + "生产了" + i + "个产品,现在库存量" + this.sto);
lock.notifyAll();
//}
}象生产者消费者对象,可以使用数组,没必要一个一个处理,多麻烦,用数组管理,循环处理方便一些另外,因为你是调用random来表示产品编号的,这样你的生产者和消费者可能产生的编号不一致,你这个random有什么特别的意义吗?
1.用synchronized (lock)是因为我觉的我用的c1 c2 p1 p2等都是 不同的实例如果用synchronized (this)的话同步会不会不起作用呢,这个我不是很清楚。
2.递归调用我绝的还是有必要的,因为如果现存量为98这时生产者又生产了4个那么就会使用wait()阻塞了,但是当别的消费者消费了1个后就会notifyAll这时那个原来没执行完的方法又从wait()往下执行,会使仓库的量变为101这样就错了。
3.random没有什么实际意义只是用来使消费者随便取,生产者随便放用的,好测试。
synchronized (lock) {
if ((this.sto + i) > max) {
System.out.println(name + "仓库已满............" + i);
try {
lock.wait();
put(i,name);//等wait结束后继续调用put方法来放置刚才生产的i个产品
} catch (InterruptedException ex) {
Logger.getLogger(Storage.class.getName()).log(Level.SEVERE, null, ex);
}
} else {
this.sto = this.sto + i;
System.out.println(name + "生产了" + i + "个产品,现在库存量" + this.sto);
lock.notifyAll();
}
}
} public void get(int i, String name) {//消费者取
synchronized (lock) {
if (this.sto - i < 0) {
System.out.println(name + "仓库余额不足............" + i);
try {
lock.wait();
get(i,name);
} catch (InterruptedException ex) {
Logger.getLogger(Storage.class.getName()).log(Level.SEVERE, null, ex);
}
} else {
this.sto = this.sto - i;
System.out.println(name + "消费了" + i + "个产品,现在库存量" + this.sto);
lock.notifyAll();
}
}
}
}你把同步都做在了 lock 上那你想想下面的情况,当容量到达100的时候 比如正有 5个写线程在 lock 上 wait 这时候, 消费者执行 ,并 notifyAll 系统选择了一个生产者来执行, 此时生产者生产了一个产品,但是此时它 notifyAll 就通知了所有在 lock 上等待的对象, 包括等待的写着线程。 写着线程可以唤醒写着线程这就是问题的所在。
其实这是个既有同步又有互斥的例子,但是在使用 synchronized 实现的时候我们可以把他当成一个同步的例子。你只需要把你的同步对象改了就行了。 比如
synchronized (lock) {
if ((this.sto + i) > max) {
System.out.println(name + "仓库已满............" + i);
try {
lock.wait();
put(i,name);//等wait结束后继续调用put方法来放置刚才生产的i个产品
} catch (InterruptedException ex) {
Logger.getLogger(Storage.class.getName()).log(Level.SEVERE, null, ex);
}
} else {
this.sto = this.sto + i;
System.out.println(name + "生产了" + i + "个产品,现在库存量" + this.sto);
lock1.notifyAll();
}
}
if (this.sto - i < 0) {
System.out.println(name + "仓库余额不足............" + i);
try {
lock1.wait();
get(i,name);
} catch (InterruptedException ex) {
Logger.getLogger(Storage.class.getName()).log(Level.SEVERE, null, ex);
}
} else {
this.sto = this.sto - i;
System.out.println(name + "消费了" + i + "个产品,现在库存量" + this.sto);
lock.notifyAll();
}
我并没有自习看你的递归调用, 但是 通过 在不同对象上同步可以解决 生产者唤醒生产者的问题。synchronized(this)不行是因为 this 表示本对象的引用,每个线程都在本对象上同步 等于没做同步。你共享的是 sto对象 我上面的代码有问题 , 忘记改 同步对象了 一会给你贴正确的。 同步要做在 sto 上 。这里需要两个同步语句。
package thread;import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;public class CustomerProducterThread { public static void main(String[] args) throws InterruptedException {
Storage storage = new Storage();
ExecutorService exec=Executors.newCachedThreadPool();
for(int i=0;i<4;i++){
exec.execute(new Producter(storage));
exec.execute(new Customer(storage));
}
TimeUnit.SECONDS.sleep(2);
exec.shutdownNow();
}
}class Storage {//仓库 public static final int[] lock = new int[0];
public static final int[] lock1= new int[0];
public static final Integer max = 100;
private Integer sto = 0; public void put(int i, String name) {//生产者放
synchronized (lock) {
if ((this.sto + i) > max) {
System.out.println(name + "仓库已满............" + i);
try {
lock.wait();
// put(i,name);//等wait结束后继续调用put方法来放置刚才生产的i个产品
} catch (InterruptedException ex) {
Logger.getLogger(Storage.class.getName()).log(Level.SEVERE, null, ex);
}
} else {
this.sto = this.sto + i;
System.out.println(name + "生产了" + i + "个产品,现在库存量" + this.sto);
}
}
synchronized(lock1){
lock1.notifyAll();
} } public void get(int i, String name) {//消费者取
synchronized (lock1) {
if (this.sto - i < 0) {
System.out.println(name + "仓库余额不足............" + i);
try {
lock1.wait();
// get(i,name);
} catch (InterruptedException ex) {
Logger.getLogger(Storage.class.getName()).log(Level.SEVERE, null, ex);
}
} else {
this.sto = this.sto - i;
System.out.println(name + "消费了" + i + "个产品,现在库存量" + this.sto);
}
}
synchronized(lock){
lock.notifyAll();
}
}
}class Customer extends Thread {//消费者 public Storage sto; public Customer(Storage sto) {
this.sto = sto;
} @Override
public void run() {
while (!Thread.interrupted()) {
sto.get(new Random().nextInt(10) + 1, Thread.currentThread().getName());
} }
}class Producter extends Thread {//生产者 public Storage sto; public Producter(Storage sto) {
this.sto = sto;
} @Override
public void run() {
while (!Thread.interrupted()) {
sto.put(new Random().nextInt(10) + 1, Thread.currentThread().getName());
} }
}
你要知道synchronized的意义,就是对一个对象加锁,你的生产者和消费者对象都使用同一个Storage对象storage,所以对这个对象同步就可以了,而你的线程刚好就是调用这个对象的方法,所以synchronized(this)就可以了,这里的this就是storage对象2
我上面理解错你的意思了,是为了让总数不超过一定的数量,所以还是需要else,不过递归没必要,因为你的线程是循环执行的,所以下一次还会进入方法,只不过这时的i可能改变了,除非你希望原来的i不改变。3
random的意义我原来看错了,不是生产消费的编号,而是随机生产和消费的数量。
如果只用一个锁 ,会出现 生产者 通知生产者的情况 所以肯定不能只在 sto 上面加锁。多人多缓生产者消费者 问题 。至少需要用两个锁来实现
生产者通知生产者有问题吗?被通知的生产者,不满足条件同样进入wait让出CPU,所以没有特殊必要,不需要采用多个锁,在notifyAll的时候,同样都存在生产者或消费者。一般的多线程,多采用队列来处理,包括线程池也有自己的队列,按你这么说,也要采用多个队列吗?具体问题具体分析,不是抱着理论人云亦云。像你的代码,采用2把锁,能体现出什么?如果生产者和消费者两个线程分别进入else代码,你还能保证同步吗?因为生产者和消费者线程锁的对象不一样,所以很有可能生产者线程和消费者线程同时进入else,因为你的代码,只是生产者排斥生产者线程(即某个生产者线程执行,另一个生产者线程没有锁权而等待),消费者排斥消费者线程,但是生产者和消费者线程并不排斥(即生产者线程执行,消费者线程也执行,这样你的库存量的控制可以说是随机的,并不是可控的),你再好好理解一下吧。
什么叫抱着理论人云亦云? 操作系统人家总结了这么多年还没你说的对?针对你的问题 我承认我代码有问题 ,看新代码?
package thread;import java.util.Random;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
import java.util.logging.Logger;public class CustomerProducterThread { public static void main(String[] args) throws InterruptedException {
Storage storage = new Storage();
ExecutorService exec=Executors.newCachedThreadPool();
for(int i=0;i<4;i++){
exec.execute(new Producter(storage));
exec.execute(new Customer(storage));
}
TimeUnit.SECONDS.sleep(2);
exec.shutdownNow();
}
}class Storage {//仓库 public static final int[] lock = new int[0];
public static final int[] lock1= new int[0];
public static final Integer max = 100;
private Integer sto = 0; public void put(int i, String name) {//生产者放
synchronized (lock) {
if ((this.sto + i) > max) {
System.out.println(name + "仓库已满............" + i);
try {
lock.wait();
// put(i,name);//等wait结束后继续调用put方法来放置刚才生产的i个产品
} catch (InterruptedException ex) {
Logger.getLogger(Storage.class.getName()).log(Level.SEVERE, null, ex);
}
} else {
synchronized(this){
this.sto = this.sto + i;
System.out.println(name + "生产了" + i + "个产品,现在库存量" + this.sto);
}
}
}
synchronized(lock1){
lock1.notifyAll();
} } public void get(int i, String name) {//消费者取
synchronized (lock1) {
if (this.sto - i < 0) {
System.out.println(name + "仓库余额不足............" + i);
try {
lock1.wait();
// get(i,name);
} catch (InterruptedException ex) {
Logger.getLogger(Storage.class.getName()).log(Level.SEVERE, null, ex);
}
} else {
synchronized(this){
this.sto = this.sto - i;
System.out.println(name + "消费了" + i + "个产品,现在库存量" + this.sto);
}
}
}
synchronized(lock){
lock.notifyAll();
}
}
}class Customer extends Thread {//消费者 public Storage sto; public Customer(Storage sto) {
this.sto = sto;
} @Override
public void run() {
while (!Thread.interrupted()) {
sto.get(new Random().nextInt(10) + 1, Thread.currentThread().getName());
} }
}class Producter extends Thread {//生产者 public Storage sto; public Producter(Storage sto) {
this.sto = sto;
} @Override
public void run() {
while (!Thread.interrupted()) {
sto.put(new Random().nextInt(10) + 1, Thread.currentThread().getName());
} }
}
我的回复是针对你的回复
如果只用一个锁 ,会出现 生产者 通知生产者的情况 所以肯定不能只在 sto 上面加锁。
叫你不要死抱着理论而不会变通,要具体问题具体分析,在这个问题上,你的多把锁体现不出任何优势。因为上面也说了,生产者和消费者可以同时进入方法,可以分别执行notifyAll,这样同样存在着生产者和消费者线程去竞争CPU。
private final ReentrantLock lock;
/** Condition for waiting takes */
private final Condition notEmpty;
/** Condition for waiting puts */
private final Condition notFull;[
这是生产者消费者队列的属性 , 至少它也用来 两个 Condition ,如果按你的意思它是不是只用一个 condition就行了? 明显的同步问题你为什么 会让生产者去唤醒生产者?
至少 生产者 不会去通知生产者吧? 你看看我的例子并行度是要比你说的高吧? 你把整个缓冲区都加锁了 ,至少生产者和消费者可以 在都满足条件的时候同时执行, 你那个把锁 直接加到 storage 上了,整个程序都被线性话了
我到觉得你说的不成立,
因为上面也说了,生产者和消费者可以同时进入方法,可以分别执行notifyAll,这样同样存在着生产者和消费者线程去竞争CPU
这中情况下的竞争是不可避免的