[color=red]线程间通讯,当有多个生产者、消费者时,容易导致的问题。[/color]
一、当只有两个线程,一个生产、一个消费的时候,数据是没有问题的,如下:
运行效果:
二、当有两个生产者、消费者时,数据出现了问题:
运行效果(第五行、第六行都为生产者):
三、如果为多个生产者和消费者,修改如下: if判断改为while判断,当线程被唤醒的时候,都要去判断一下flag; 并把notify 改为notifyAll唤醒线程,不管生产者还是消费者都唤醒。
运行效果:
一、当只有两个线程,一个生产、一个消费的时候,数据是没有问题的,如下:
package com.zzl.thread;
class MyResource{
private String name;
private int number = 1;
private boolean flag = false;
public synchronized void set(String name){
if(flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.name = name +"......"+ number++;
System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name);
this.flag = true;
this.notify();
}
public synchronized void print(){
if(!flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"---------消费者---------"+this.name);
this.flag = false;
this.notify();
}
}
class Producer implements Runnable{
private MyResource r;
public Producer(MyResource r){
this.r = r;
}
@Override
public void run() {
while(true){
r.set("苹果");
}
}
}
class Consumer implements Runnable{
private MyResource r;
public Consumer(MyResource r){
this.r = r;
}
@Override
public void run() {
while(true){
r.print();
}
}
}
public class ProducerConsumerDemo {
public static void main(String[] args) {
MyResource r = new MyResource();
Producer p = new Producer(r);
Consumer c = new Consumer(r);
Thread t1 = new Thread(p);
Thread t2 = new Thread(c);
t1.start();
t2.start();
}
}
运行效果:
Thread-1---------消费者---------苹果......40535
Thread-0...生产者...苹果......40536
Thread-1---------消费者---------苹果......40536
Thread-0...生产者...苹果......40537
Thread-1---------消费者---------苹果......40537
Thread-0...生产者...苹果......40538
Thread-1---------消费者---------苹果......40538
Thread-0...生产者...苹果......40539
Thread-1---------消费者---------苹果......40539
Thread-0...生产者...苹果......40540
Thread-1---------消费者---------苹果......40540
Thread-0...生产者...苹果......40541
Thread-1---------消费者---------苹果......40541
Thread-0...生产者...苹果......40542
Thread-1---------消费者---------苹果......40542
Thread-0...生产者...苹果......40543
Thread-1---------消费者---------苹果......40543
Thread-0...生产者...苹果......40544
Thread-1---------消费者---------苹果......40544
二、当有两个生产者、消费者时,数据出现了问题:
package com.zzl.thread;
class MyResource{
private String name;
private int number = 1;
private boolean flag = false;
public synchronized void set(String name){
if(flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.name = name +"......"+ number++;
System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name);
this.flag = true;
this.notify();
}
public synchronized void print(){
if(!flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"---------消费者---------"+this.name);
this.flag = false;
this.notify();
}
}
class Producer implements Runnable{
private MyResource r;
public Producer(MyResource r){
this.r = r;
}
@Override
public void run() {
while(true){
r.set("苹果");
}
}
}
class Consumer implements Runnable{
private MyResource r;
public Consumer(MyResource r){
this.r = r;
}
@Override
public void run() {
while(true){
r.print();
}
}
}
public class ProducerConsumerDemo {
public static void main(String[] args) {
MyResource r = new MyResource();
Producer p = new Producer(r);
Consumer c = new Consumer(r);
Thread t1 = new Thread(p);
Thread t2 = new Thread(p);
Thread t3 = new Thread(c);
Thread t4 = new Thread(c);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
运行效果(第五行、第六行都为生产者):
Thread-0...生产者...苹果......19803
Thread-2---------消费者---------苹果......19803
Thread-0...生产者...苹果......19804
Thread-2---------消费者---------苹果......19804
Thread-0...生产者...苹果......19805
Thread-1...生产者...苹果......19806
Thread-3---------消费者---------苹果......19806
Thread-1...生产者...苹果......19807
Thread-3---------消费者---------苹果......19807
Thread-1...生产者...苹果......19808
Thread-3---------消费者---------苹果......19808
Thread-1...生产者...苹果......19809
Thread-3---------消费者---------苹果......19809
三、如果为多个生产者和消费者,修改如下: if判断改为while判断,当线程被唤醒的时候,都要去判断一下flag; 并把notify 改为notifyAll唤醒线程,不管生产者还是消费者都唤醒。
package com.zzl.thread;
class MyResource{
private String name;
private int number = 1;
private boolean flag = false;
public synchronized void set(String name){
while(flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
this.name = name +"......"+ number++;
System.out.println(Thread.currentThread().getName()+"...生产者..."+this.name);
this.flag = true;
this.notifyAll();
}
public synchronized void print(){
while(!flag){
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
System.out.println(Thread.currentThread().getName()+"---------消费者---------"+this.name);
this.flag = false;
this.notifyAll();
}
}
class Producer implements Runnable{
private MyResource r;
public Producer(MyResource r){
this.r = r;
}
@Override
public void run() {
while(true){
r.set("苹果");
}
}
}
class Consumer implements Runnable{
private MyResource r;
public Consumer(MyResource r){
this.r = r;
}
@Override
public void run() {
while(true){
r.print();
}
}
}
public class ProducerConsumerDemo {
public static void main(String[] args) {
MyResource r = new MyResource();
Producer p = new Producer(r);
Consumer c = new Consumer(r);
Thread t1 = new Thread(p);
Thread t2 = new Thread(p);
Thread t3 = new Thread(c);
Thread t4 = new Thread(c);
t1.start();
t2.start();
t3.start();
t4.start();
}
}
运行效果:
Thread-0...生产者...苹果......20549
Thread-2---------消费者---------苹果......20549
Thread-1...生产者...苹果......20550
Thread-3---------消费者---------苹果......20550
Thread-0...生产者...苹果......20551
Thread-2---------消费者---------苹果......20551
Thread-1...生产者...苹果......20552
Thread-3---------消费者---------苹果......20552
Thread-0...生产者...苹果......20553
Thread-2---------消费者---------苹果......20553
Thread-1...生产者...苹果......20554
Thread-3---------消费者---------苹果......20554