【多线程07】生产者消费者(Lock锁对等待唤醒机制和同步的改进)

主宰稳场 提交于 2019-12-10 07:57:08

1.提出问题

在上个博客中,使用等待唤醒机制,可以达到一进一出的效果,可是实际的开发中,不止两个线程,一般都会多个线程,那么此时会出现什么问题???

class Resource {
    private String name;
    private int count = 1;
    private boolean flag = false;

    public synchronized void set(String name) {
        if (flag) {
            try {
               wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        this.name = name + "......" + count++;
        System.out.println(Thread.currentThread().getName() + "生产者...." + this.name);
        flag = true;
        notify();
    }

    public synchronized void out(){
        if(!flag){
            try {
                wait();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
        System.out.println(Thread.currentThread().getName()+"消费者......"+this.name);
        flag=false;
        notify();
    }
}

class Producer implements Runnable{
    private Resource resource;

    public Producer(Resource resource) {
        this.resource = resource;
    }

    @Override
    public void run() {
        while (true){
            resource.set("+商品+");
        }
    }
}

class Consumer implements Runnable{
    private Resource resource;

    public Consumer (Resource resource) {
        this.resource = resource;
    }

    @Override
    public void run() {
        while (true){
            resource.out();
        }
    }
}

public class ProducerConsumerDemo {
    public static void main(String[] args) {
        Resource resource = new Resource();
        Thread t1 = new Thread(new Producer(resource));
        Thread t2 = new Thread(new Producer(resource));
        Thread t3 = new Thread(new Consumer(resource));
        Thread t4 = new Thread(new Consumer(resource));
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

在这里插入图片描述

2.原因分析

在这里插入图片描述
在这里插入图片描述
可能有个疑问,t2由于判断过标记,所以唤醒以后不再判断标记,直接执行if语句块中的内容,那么为什么换成while以后就会回去判断这个标记了呢?
这跟while语法有关,下面补充一下if和while的本质区别:
在这里插入图片描述
现在将if改成while后,会出现什么问题?
在这里插入图片描述
原因在于notify()只会唤醒本方的线程,应该唤醒对方的线程。所以改为notifyAll()
最终Resource程序为:

class Resource {
    private String name;
    private int count = 1;
    private boolean flag = false;

    public synchronized void set(String name) {
        while (flag) {
            try { wait();} catch (InterruptedException e){ e.printStackTrace(); }
        }
        this.name = name + "......" + count++;
        System.out.println(Thread.currentThread().getName() + "生产者...." + this.name);
        flag = true;
        notifyAll();
    }

    public synchronized void out(){
        while (!flag){
            try { wait();} catch (InterruptedException e){ e.printStackTrace(); }
        }
        System.out.println(Thread.currentThread().getName()+"消费者......"+this.name);
        flag=false;
        notifyAll();
    }
}

在这里插入图片描述

4.使用Lock锁改进上述程序

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
下面的代码是将上面的代码完全替换成lock的形式:

class Resource {
    private String name;
    private int count = 1;
    private boolean flag = false;
    private Lock lock = new ReentrantLock();

    private Condition condition = lock.newCondition();


    public  void set(String name) throws InterruptedException {
        lock.lock();
        try{
            while (flag) {
              condition.await();
            }
            this.name = name + "......" + count++;
            System.out.println(Thread.currentThread().getName() + "生产者...." + this.name);
            flag = true;
            condition.signalAll();
        }finally {
            lock.unlock();
        }
    }

    public  void out() throws InterruptedException {
        lock.lock();
        try {
            while (!flag){
                condition.await();
            }
            System.out.println(Thread.currentThread().getName()+"消费者......"+this.name);
            condition.signalAll();
            flag=false;
        } finally {
            lock.unlock();
        }
    }
}

class Producer implements Runnable{
    private Resource resource;

    public Producer(Resource resource) {
        this.resource = resource;
    }

    @Override
    public void run() {
        while (true){
            try {
                resource.set("+商品+");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Consumer implements Runnable{
    private Resource resource;

    public Consumer (Resource resource) {

        this.resource = resource;
    }

    @Override
    public void run() {
        while (true){
            try {
                resource.out();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class ProducerConsumerDemo {
    public static void main(String[] args) {
        Resource resource = new Resource();
        Thread t1 = new Thread(new Producer(resource));
        Thread t2 = new Thread(new Producer(resource));
        Thread t3 = new Thread(new Consumer(resource));
        Thread t4 = new Thread(new Consumer(resource));
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}

但是还是唤醒了本方的线程,现在只想唤醒对方的线程:

class Resource {
    private String name;
    private int count = 1;
    private boolean flag = false;
    private Lock lock = new ReentrantLock();

    private Condition condition_producer = lock.newCondition();
    private Condition condition_consumer = lock.newCondition();


    public  void set(String name) throws InterruptedException {
        lock.lock();
        try{
            while (flag) {
              condition_producer.await();
            }
            this.name = name + "......" + count++;
            System.out.println(Thread.currentThread().getName() + "生产者...." + this.name);
            flag = true;
            condition_consumer.signalAll();
        }finally {
            lock.unlock();
        }
    }

    public  void out() throws InterruptedException {
        lock.lock();
        try {
            while (!flag){
                condition_consumer.await();
            }
            System.out.println(Thread.currentThread().getName()+"消费者......"+this.name);
            condition_producer.signalAll();
            flag=false;
        } finally {
            lock.unlock();
        }
    }
}

class Producer implements Runnable{
    private Resource resource;

    public Producer(Resource resource) {
        this.resource = resource;
    }

    @Override
    public void run() {
        while (true){
            try {
                resource.set("+商品+");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

class Consumer implements Runnable{
    private Resource resource;

    public Consumer (Resource resource) {

        this.resource = resource;
    }

    @Override
    public void run() {
        while (true){
            try {
                resource.out();
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        }
    }
}

public class ProducerConsumerDemo {
    public static void main(String[] args) {
        Resource resource = new Resource();
        Thread t1 = new Thread(new Producer(resource));
        Thread t2 = new Thread(new Producer(resource));
        Thread t3 = new Thread(new Consumer(resource));
        Thread t4 = new Thread(new Consumer(resource));
        t1.start();
        t2.start();
        t3.start();
        t4.start();
    }
}
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!