这是个经典的例子,所以必会。
1、使用wait和signalAll
仓库类:
/**
* 仓库有两个方法,加和减
*/
public class StoreManager {
private static final int MAX_NUM = 100;// 仓库最大容量
private int currentNum;
public StoreManager(int n) {
this.currentNum = n;
}
public synchronized void addProduct(int amount) {
while (currentNum + amount > MAX_NUM) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
currentNum += amount;
System.out.println("生产了:" + amount + "个" + ",当前容量有:" + currentNum + "个");
notifyAll();
}
public synchronized void takeProduct(int amount) {
while (currentNum < amount) {
try {
this.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
currentNum -= amount;
System.out.println("消费了:" + amount + "个" + ",当前容量有:" + currentNum + "个");
notifyAll();
}
}
生产者线程:
public class Producer implements Runnable {
private int amount;
private StoreManager sm;
public Producer(int a, StoreManager sm) {
this.amount = a;
this.sm = sm;
}
@Override
public void run() {
sm.addProduct(amount);
}
}
消费者线程:
public class Consumer implements Runnable {
private int amount;
private StoreManager sm;
public Consumer(int a, StoreManager sm) {
this.amount = a;
this.sm = sm;
}
@Override
public void run() {
sm.takeProduct(amount);
}
}
测试
public class Test {
public static void main(String[] args) {
StoreManager sm = new StoreManager(0);
for (int i = 0; i < 3; i++) {
int a = (int) (Math.random() * 20)+1;
Thread t = new Thread(new Consumer(a, sm));
t.start();
}
for (int i = 0; i < 5; i++) {
int a = (int) (Math.random() * 20)+1;
Thread t = new Thread(new Producer(a, sm));
t.start();
}
}
}
结果
加入生产者少于消费者,则线程会挂起,因为这里使用了有限的循环,实际可能是无限的。
生产了:1个,当前容量有:1个
生产了:16个,当前容量有:17个
生产了:18个,当前容量有:35个
生产了:14个,当前容量有:49个
消费了:7个,当前容量有:42个
消费了:14个,当前容量有:28个
消费了:9个,当前容量有:19个
生产了:9个,当前容量有:28个
2、使用BlockingQueue
仓库类
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
public class StoreManager {
private BlockingQueue<Integer> bq;
public StoreManager() {
bq = new LinkedBlockingQueue<>();
}
public BlockingQueue<Integer> getBlockQueue() {
return bq;
}
}
生产者
public class Producer implements Runnable {
private int number;
private final BlockingQueue<Integer> bq;
public Producer(int n, BlockingQueue<Integer> bq) {
this.number = n;
this.bq = bq;
}
@Override
public void run() {
try {
bq.put(number);
// System.out.println("生产了数字:" + number);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
消费者
public class Consumer implements Runnable {
private final BlockingQueue<Integer> bq;
public Consumer(BlockingQueue<Integer> bq) {
this.bq = bq;
}
@Override
public void run() {
try {
System.out.println("消费了数字:" + bq.take());
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
测试
public class Test {
public static void main(String[] args) {
StoreManager sm = new StoreManager();
for (int i = 0; i < 5; i++) {
Thread t = new Thread(new Consumer(sm.getBlockQueue()));
t.start();
}
for (int i = 0; i < 5; i++) {
int n = (int) (Math.random() * 100) + 1;
Thread t = new Thread(new Producer(n, sm.getBlockQueue()));
t.start();
}
}
}
结果
由于输出和bq.put()可能会被拆分,所以就不打印了。
另外:BlockingQueue是一个一个生产消费的。
消费了数字:60
消费了数字:69
消费了数字:59
消费了数字:4
消费了数字:19
3、使用ReentrantLock和Condition
仓库类:
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;
public class StoreManager {
private static final int MAX_NUM = 100;// 仓库最大容量
private int currentNum;
private ReentrantLock lock;
private Condition condition;
public StoreManager(int n) {
this.currentNum = n;
lock = new ReentrantLock();
condition = lock.newCondition();
}
public void addProduct(int amount) {
lock.lock();
try {
while (currentNum + amount > MAX_NUM) {
System.out.println("仓库满了...");
condition.await();
}
currentNum += amount;
System.out.println("生产了:" + amount + "个" + ",当前容量有:" + currentNum + "个");
condition.signalAll();
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
public void takeProduct(int amount) {
lock.lock();
try {
while (currentNum < amount) {
System.out.println("仓库数量不够,不能取...");
condition.await();
}
currentNum -= amount;
System.out.println("消费了:" + amount + "个" + ",当前容量有:" + currentNum + "个");
condition.signalAll();
} catch (InterruptedException e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}
生产者
public class Producer implements Runnable {
private int amount;
private StoreManager sm;
public Producer(int a, StoreManager sm) {
this.amount = a;
this.sm = sm;
}
@Override
public void run() {
sm.addProduct(amount);
}
}
消费者
public class Consumer implements Runnable {
private int amount;
private StoreManager sm;
public Consumer(int a, StoreManager sm) {
this.amount = a;
this.sm = sm;
}
@Override
public void run() {
sm.takeProduct(amount);
}
}
测试
public class Test {
public static void main(String[] args) {
StoreManager sm = new StoreManager(0);
for (int i = 0; i < 4; i++) {
int a = (int) (Math.random() * 20) + 1;
Thread t = new Thread(new Consumer(a, sm));
t.start();
}
for (int i = 0; i < 5; i++) {
int a = (int) (Math.random() * 20) + 1;
Thread t = new Thread(new Producer(a, sm));
t.start();
}
}
}
结果
仓库数量不够,不能取...
仓库数量不够,不能取...
仓库数量不够,不能取...
仓库数量不够,不能取...
生产了:20个,当前容量有:20个
生产了:2个,当前容量有:22个
消费了:7个,当前容量有:15个
生产了:12个,当前容量有:27个
消费了:6个,当前容量有:21个
消费了:12个,当前容量有:9个
消费了:1个,当前容量有:8个
生产了:11个,当前容量有:19个
生产了:11个,当前容量有:30个