生产者与消费者问题(两种方法实现)

场景:

生产者(Producer)生产产品,送到中间商(Medium)那里,消费者(Customer)从中间商那里取走产品,中间商只能持有一定数量的产品(如:30),如果中间商那里已经有了30个产品,中间商会通知生产者等一下,店中有空位置放产品时,通知生产者继续生产,如果中间商那里没有产品了,会通知消费者等一下,中间商有产品了,通知消费者继续消费。

Synchronized方法实现生产者消费者问题:

涉及到的线程间通信的方法

wait

导致当前线程等待,直到另一个线程调用该对象的notify()方法或notifyAll()方法。当前的线程必须拥有该对象的监视器。 该线程释放此监视器的所有权,并等待另一个线程通知等待该对象监视器的线程通过调用notify方法或notifyAll方法notifyAll方法 。 然后线程等待,直到它可以重新获得监视器的所有权并恢复执行。

notify

唤醒正在等待对象监视器的单个线程。 如果任何线程正在等待这个对象,其中一个被选择被唤醒。 选择是任意的,并且由实施的判断发生。 线程通过调用wait方法之一等待对象的监视器。调用notify后,当前线程不会马上释放该对象锁,要等到程序退出同步块后,当前线程才会释放锁。

notifyAll
该方法与 notify ()方法的工作方式相同,重要的一点差异是:
notifyAll 使所有原来在该对象上 wait 的线程统统退出等待状态,使得他们全部从等待队列中移入到同步队列中去,等待下一次能够有机会获取到对象监视器锁。

代码

/**
 * 中间商
 */
public class Medium {
     
    private int num = 0;
    private static final int TOTAL = 30;

    /**
     * 接收生产数据
     */
    public synchronized void put() {
     
        if (num < TOTAL) {
     
            System.out.println(Thread.currentThread() + "增加库存--------当前库存" + ++num);
            notifyAll();
        } else {
     
            System.out.println(Thread.currentThread() + "增加库存--------库存已满" + num);
            try {
     
                wait();
            } catch (InterruptedException e) {
     
                e.printStackTrace();
            }
        }
    }

    /**
     * 获取消费者数据
     */
    public synchronized void take() {
     
        if (num > 0) {
     
            System.out.println(Thread.currentThread() + "消费库存--------当前库存" + --num);
            notifyAll();
        } else {
     
            System.out.println(Thread.currentThread() + "消费库存--------库存不足" + num);
            try {
     
                wait();
            } catch (InterruptedException e) {
     
                e.printStackTrace();
            }
        }
    }
}
/**
 * 生产者
 */
public class Producer implements Runnable{
     

    private Medium medium;

    public Producer(Medium medium) {
     
        this.medium = medium;
    }

    @Override
    public void run() {
     
        while (true) {
     
            medium.put();
        }
    }
}
/**
 * 消费者
 */
public class Consumer implements Runnable {
     
    private Medium medium;

    public Consumer(Medium medium) {
     
        this.medium = medium;
    }

    @Override
    public void run() {
     
        while (true) {
     
            medium.take();
        }
    }
}
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 测试类
 */
public class Main {
     
    public static void main(String[] agrs) {
     
        Medium medium = new Medium();

        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 20, 3L, TimeUnit.SECONDS,new LinkedBlockingQueue<>(20), new ThreadPoolExecutor.DiscardOldestPolicy());
        threadPoolExecutor.prestartAllCoreThreads();

        for (int i = 0; i < 5; i++){
     
            threadPoolExecutor.submit(new Producer(medium));
        }

        for (int i = 0; i < 10; i++){
     
            threadPoolExecutor.submit(new Consumer(medium));
        }
    }
}

Lock方法实现生产者消费者问题:

涉及到的方法

lock

需要显示指定起始位置和终止位置。一般使用ReentrantLock类做为锁,多个线程中必须要使用一个。

ReentrantLock

ReentrantLock类做为对象才能保证锁的生效。且在加锁和解锁处需要通过lock()和unlock()显示指出。所以一般会在finally块中写unlock()以防死锁。

代码

/**
 * 中间商
 */
public class Medium {
     
    private int num = 0;
    private static final int TOTAL = 30;

    private Lock lock = new ReentrantLock();
    private Condition consumerCondition = lock.newCondition();
    private Condition producerCondition = lock.newCondition();

    /**
     * 接收生产数据
     */
    public void put() {
     
        lock.lock();
        try {
     
            if (num < TOTAL) {
     
                System.out.println(Thread.currentThread() + "增加库存--------当前库存" + ++num);
                consumerCondition.signalAll();
            } else {
     
                System.out.println(Thread.currentThread() + "增加库存--------库存已满" + num);
                try {
     
                    producerCondition.await();
                } catch (InterruptedException e) {
     
                    e.printStackTrace();
                }
            }
        } finally {
     
            lock.unlock();
        }
    }

    /**
     * 获取消费者数据
     */
    public void take() {
     
        lock.lock();
        try {
     
            if (num > 0) {
     
                System.out.println(Thread.currentThread() + "消费库存--------当前库存" + --num);
                producerCondition.signalAll();
            } else {
     
                System.out.println(Thread.currentThread() + "消费库存--------库存不足" + num);
                try {
     
                    consumerCondition.await();
                } catch (InterruptedException e) {
     
                    e.printStackTrace();
                }
            }
        } finally {
     
            lock.unlock();
        }
    }

}
/**
 * 生产者
 */
public class Producer implements Runnable{
     

    private Medium medium;

    public Producer(Medium medium) {
     
        this.medium = medium;
    }

    @Override
    public void run() {
     
        while (true) {
     
            medium.put();
        }
    }
}
/**
 * 消费者
 */
public class Consumer implements Runnable {
     
    private Medium medium;

    public Consumer(Medium medium) {
     
        this.medium = medium;
    }

    @Override
    public void run() {
     
        while (true) {
     
            medium.take();
        }
    }
}
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

/**
 * 测试类
 */
public class Main {
     
    public static void main(String[] agrs) {
     
        Medium medium = new Medium();

        ThreadPoolExecutor threadPoolExecutor = new ThreadPoolExecutor(10, 20, 3L, TimeUnit.SECONDS,new LinkedBlockingQueue<>(20), new ThreadPoolExecutor.DiscardOldestPolicy());
        threadPoolExecutor.prestartAllCoreThreads();

        for (int i = 0; i < 5; i++){
     
            threadPoolExecutor.submit(new Producer(medium));
        }

        for (int i = 0; i < 10; i++){
     
            threadPoolExecutor.submit(new Consumer(medium));
        }
    }
}

Synchronized和lock用途区别

Synchronized语句和ReentrantLock在一般情况下区别不大,但是在非常复杂的同步应用中和需要实现公平锁功能时,请考虑使用ReentrantLock。

你可能感兴趣的:(并发编程)