生产者和消费者

生产者和消费者

1.使用synchronized和wait和notifyAll方法实现

代码如下:

public class ProducerConsumer {
     
    public static void main(String[] args) {
     
        WareHouse wareHouse = new WareHouse();
        Thread producer = new Thread(new Producer(wareHouse));
        Thread consumer = new Thread(new Consumer(wareHouse));

        producer.setName("producer");
        consumer.setName("consumer");
        
        producer.start();
        consumer.start();

    }
}

class WareHouse{
     
    private int data=0;

    //生产商品
    public synchronized void pro(){
     
        if (data!=0){
        //使用if会产生虚假唤醒现象
            try {
     
                this.wait();
            } catch (InterruptedException e) {
     
                e.printStackTrace();
            }
        }
        data++;
        System.out.println(Thread.currentThread().getName()+"---->"+data);
        this.notifyAll();
    }

    //消费商品
    public synchronized void con(){
     
        if (data==0){
       //使用if会产生虚假唤醒现象
            try {
     
                this.wait();
            } catch (InterruptedException e) {
     
                e.printStackTrace();
            }
        }
        data--;
        System.out.println(Thread.currentThread().getName()+"---->"+data);
        this.notifyAll();
    }
}

//生产者线程
class Producer implements Runnable{
     
    private WareHouse wareHouse;

    public Producer(WareHouse wareHouse){
     
        this.wareHouse = wareHouse;
    }

    @Override
    public void run() {
     
        //模拟一直生产
        while(true){
     
            wareHouse.pro();
        }
    }
}

//消费者线程
class Consumer implements Runnable{
     
    private WareHouse wareHouse;

    public Consumer(WareHouse wareHouse){
     
        this.wareHouse = wareHouse;
    }
    @Override
    public void run() {
     
        //模拟一直消费
        while(true){
     
            wareHouse.con();
        }
    }
}

测试结果:

生产者线程和消费者线程都只有一个的时候
结果正常
生产者和消费者_第1张图片
将消费者线程和生产者线程都增加为两个

        WareHouse wareHouse = new WareHouse();
        Thread producer = new Thread(new Producer(wareHouse));
        Thread consumer = new Thread(new Consumer(wareHouse));
        Thread producer1 = new Thread(new Producer(wareHouse));
        Thread consumer1 = new Thread(new Consumer(wareHouse));
        producer.setName("producer");
        consumer.setName("consumer");
        producer1.setName("producer1");
        consumer1.setName("consumer1");
        producer.start();
        consumer.start();
        producer1.start();
        consumer1.start();

测试结果:
结果中出现了2 很明显出现了虚假唤醒的情况解决这种情况应该将if (data == 0)和if(data != 0 )改为while(data==0)和while(data!=0)
生产者和消费者_第2张图片
出现虚假唤醒的原因: 在生产者和消费者线程都有多个的情况下,当一个生产者线程抢到了线程琐进入了if代码块并且执行了this.wait()释放了线程琐,此时另一个生产者线程又抢到了线程琐也进入了if代码块执行了wait方法释放了琐,那么目前就有多个生产者线程在if代码块中,当消费者线程执行完释放琐之后,目前的多个生产者线程就不用再进行if判断只要抢到琐就执行生产方法,如果生产者线程一直抢到琐 那么在if语句块中休眠的生产者线程就会全部连续执行生产方法导致data值超过1。同时消费者线程也可能会发生这种情况导致data值为负数。

修改后的代码:

public class ProducerConsumer {
     
    public static void main(String[] args) {
     
        WareHouse wareHouse = new WareHouse();
        Thread producer = new Thread(new Producer(wareHouse));
        Thread consumer = new Thread(new Consumer(wareHouse));
        Thread producer1 = new Thread(new Producer(wareHouse));
        Thread consumer1 = new Thread(new Consumer(wareHouse));
        producer.setName("producer");
        consumer.setName("consumer");
        producer1.setName("producer1");
        consumer1.setName("consumer1");
        producer.start();
        consumer.start();
        producer1.start();
        consumer1.start();

    }
}

class WareHouse{
     
    private int data=0;

    //生产商品
    public synchronized void pro(){
     
        while (data!=0){
        //使用if会产生虚假唤醒现象
            try {
     
                this.wait();
            } catch (InterruptedException e) {
     
                e.printStackTrace();
            }
        }
        data++;
        System.out.println(Thread.currentThread().getName()+"---->"+data);
        this.notifyAll();
    }

    //消费商品
    public synchronized void con(){
     
        while (data==0){
       //使用if会产生虚假唤醒现象
            try {
     
                this.wait();
            } catch (InterruptedException e) {
     
                e.printStackTrace();
            }
        }
        data--;
        System.out.println(Thread.currentThread().getName()+"---->"+data);
        this.notifyAll();
    }
}

//生产者线程
class Producer implements Runnable{
     
    private WareHouse wareHouse;

    public Producer(WareHouse wareHouse){
     
        this.wareHouse = wareHouse;
    }

    @Override
    public void run() {
     
        //模拟一直生产
        while(true){
     
            wareHouse.pro();
        }
    }
}

//消费者线程
class Consumer implements Runnable{
     
    private WareHouse wareHouse;

    public Consumer(WareHouse wareHouse){
     
        this.wareHouse = wareHouse;
    }
    @Override
    public void run() {
     
        //模拟一直消费
        while(true){
     
            wareHouse.con();
        }
    }
}

2.使用Lock琐和Condition中的await和signalAll方法实现

代码如下:
仅仅改动了加锁方式和将wait和notifyAll替换成了await和signalAll方法

public class ProducerConsumerLock {
     
    public static void main(String[] args) {
     
        WareHouseLock wareHouseLock = new WareHouseLock();
        new Thread(()->{
     
           while(true){
     
               wareHouseLock.pro();
           }
        },"producer").start();

        new Thread(()->{
     
           while(true){
     
               wareHouseLock.con();
           }
        },"consumer").start();
    }

}

class WareHouseLock{
     
    private int data;

    Lock lock = new ReentrantLock();

    Condition condition = lock.newCondition();

    //生产
    public void pro() {
     
        lock.lock();
        try {
     
            while (data != 0) {
     
                condition.await();
            }
            data++;
            System.out.println(Thread.currentThread().getName() + data);
            condition.signalAll();
        } catch (InterruptedException e) {
     
            e.printStackTrace();
        } finally {
     
            lock.unlock();
        }
    }
    //消费
    public void con(){
     
        lock.lock(); //上锁
        try{
     
            while(data==0){
     
                condition.await();
            }
            data--;
            System.out.println(Thread.currentThread().getName()+data);
            condition.signalAll();
        }catch (InterruptedException e){
     
            e.printStackTrace();
        }finally {
     
            lock.unlock(); //解锁
        }
    }
}

测试结果:
生产者和消费者_第3张图片

你可能感兴趣的:(多线程,java,lock,synchronized)