生产者(Producer)生产产品,送到中间商(Medium)那里,消费者(Customer)从中间商那里取走产品,中间商只能持有一定数量的产品(如:30),如果中间商那里已经有了30个产品,中间商会通知生产者等一下,店中有空位置放产品时,通知生产者继续生产,如果中间商那里没有产品了,会通知消费者等一下,中间商有产品了,通知消费者继续消费。
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
需要显示指定起始位置和终止位置。一般使用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语句和ReentrantLock在一般情况下区别不大,但是在非常复杂的同步应用中和需要实现公平锁功能时,请考虑使用ReentrantLock。