生产者与消费者
生产者消费者问题属于 java 的多线程同步问题,因为涉及多线程之间对同一个资源的访问与操作,java 提供了 wait(),notify(),notifyAll() 等方法来实现多线程之间的同步问题。
生产者
负责对同一资源的生产增加操作。先判断资源数量是否已经达到最大值,如果没有达到则生产资源并调用 notifyAll() 唤醒其他线程;如果有达到则调用对象的 wati() 方法进入阻塞状态,等待被其他线程唤醒。
消费者
负责对同一资源的消费减少操作。先判断资源数量是否已经为 0,如果没有达到则消费资源并调用 notifyAll() 唤醒其他线程;如果有达到则调用对象的 wait() 方法进入阻塞状态,等待被其他线程唤醒。
夜王与守夜人
以权力的游戏里的夜王和守夜人为例,夜王就是一个生产者,负责生产异鬼;而守夜人就是一个消费者,负责消灭异鬼;异鬼就是他们之间共同操作的资源。
示例代码:
package multithreading;
/**
* 权力的游戏之夜王与守夜人之间的战争
*/
public class GofTest {
public static void main(String[] args) {
// 初始化异鬼
WhiteWalker whiteWalker = new WhiteWalker();
// 夜王诞生
Runnable nightKing = new NightKing(whiteWalker);
// 守夜人出场
Runnable nightWatch = new NightWatch(whiteWalker);
// 夜王开始行动
new Thread(nightKing).start();
// 守夜人跟上
new Thread(nightWatch).start();
// 夜王开始行动
new Thread(nightKing).start();
// 守夜人跟上
new Thread(nightWatch).start();
// 夜王开始行动
new Thread(nightKing).start();
// 守夜人跟上
new Thread(nightWatch).start();
}
}
/**
* 异鬼类
*/
class WhiteWalker {
/**
* 数量
*/
private static Integer count = 0;
/**
* 最多 10 个
*/
private static final Integer MAX = 10;
/**
* 北境长城(锁对象)
*/
private static Object greatWall = new Object();
/**
* 生产夜鬼
*/
public void create() {
// 北境长城作为锁对象
synchronized (greatWall) {
// 判断异鬼是否已经满了
while (count == MAX) {
try {
// 如果满了,则停止生产,进入阻塞
greatWall.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 如果没满,则生产
count++;
System.out.println(Thread.currentThread().getName() + "夜王生产者生产异鬼,目前共有" + count);
// 提醒守夜人消费者消费,唤醒所有线程
greatWall.notifyAll();
}
}
/**
* 杀异鬼
*/
public void kill() {
// 北境长城作为锁对象
synchronized (greatWall) {
// 判断异鬼是否已经杀完
while (count == 0) {
try {
// 杀完则等待,线程阻塞
greatWall.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
// 如果没杀完,则杀之
count--;
System.out.println(Thread.currentThread().getName() + "守夜人消费者杀异鬼,目前共有" + count);
// 唤醒所有线程,昭告天下,消灭了异鬼
greatWall.notifyAll();
}
}
}
/**
* 夜王生产者类,实现 Runnable,负责生产异鬼
*/
class NightKing implements Runnable {
private WhiteWalker whiteWalker;
public NightKing(WhiteWalker whiteWalker) {
this.whiteWalker = whiteWalker;
}
@Override
public void run() {
// 调用 10 次
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 召唤异鬼
this.whiteWalker.create();
}
}
}
/**
* 守夜人消费者类,实现 Runnable,负责杀死(消费)异鬼
*/
class NightWatch implements Runnable {
private WhiteWalker whiteWalker;
public NightWatch(WhiteWalker whiteWalker) {
this.whiteWalker = whiteWalker;
}
@Override
public void run() {
// 调用 10 次
for (int i = 0; i < 10; i++) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 消灭异鬼
this.whiteWalker.kill();
}
}
}
测试输出:
Thread-2夜王生产者生产异鬼,目前共有1
Thread-3守夜人消费者杀异鬼,目前共有0
Thread-4夜王生产者生产异鬼,目前共有1
Thread-1守夜人消费者杀异鬼,目前共有0
Thread-0夜王生产者生产异鬼,目前共有1
Thread-5守夜人消费者杀异鬼,目前共有0
Thread-2夜王生产者生产异鬼,目前共有1
Thread-3守夜人消费者杀异鬼,目前共有0
Thread-0夜王生产者生产异鬼,目前共有1
Thread-4夜王生产者生产异鬼,目前共有2
Thread-1守夜人消费者杀异鬼,目前共有1
Thread-5守夜人消费者杀异鬼,目前共有0
Thread-2夜王生产者生产异鬼,目前共有1
Thread-3守夜人消费者杀异鬼,目前共有0
Thread-4夜王生产者生产异鬼,目前共有1
Thread-5守夜人消费者杀异鬼,目前共有0
Thread-0夜王生产者生产异鬼,目前共有1
Thread-1守夜人消费者杀异鬼,目前共有0
Thread-0夜王生产者生产异鬼,目前共有1
Thread-2夜王生产者生产异鬼,目前共有2
Thread-5守夜人消费者杀异鬼,目前共有1
Thread-4夜王生产者生产异鬼,目前共有2
Thread-1守夜人消费者杀异鬼,目前共有1
Thread-3守夜人消费者杀异鬼,目前共有0
Thread-2夜王生产者生产异鬼,目前共有1
Thread-3守夜人消费者杀异鬼,目前共有0
Thread-4夜王生产者生产异鬼,目前共有1
Thread-1守夜人消费者杀异鬼,目前共有0
Thread-0夜王生产者生产异鬼,目前共有1
Thread-5守夜人消费者杀异鬼,目前共有0
Thread-2夜王生产者生产异鬼,目前共有1
Thread-3守夜人消费者杀异鬼,目前共有0
Thread-0夜王生产者生产异鬼,目前共有1
Thread-5守夜人消费者杀异鬼,目前共有0
Thread-4夜王生产者生产异鬼,目前共有1
Thread-1守夜人消费者杀异鬼,目前共有0
Thread-4夜王生产者生产异鬼,目前共有1
Thread-3守夜人消费者杀异鬼,目前共有0
Thread-0夜王生产者生产异鬼,目前共有1
Thread-5守夜人消费者杀异鬼,目前共有0
Thread-2夜王生产者生产异鬼,目前共有1
Thread-1守夜人消费者杀异鬼,目前共有0
Thread-2夜王生产者生产异鬼,目前共有1
Thread-0夜王生产者生产异鬼,目前共有2
Thread-3守夜人消费者杀异鬼,目前共有1
Thread-5守夜人消费者杀异鬼,目前共有0
Thread-4夜王生产者生产异鬼,目前共有1
Thread-1守夜人消费者杀异鬼,目前共有0
Thread-0夜王生产者生产异鬼,目前共有1
Thread-3守夜人消费者杀异鬼,目前共有0
Thread-4夜王生产者生产异鬼,目前共有1
Thread-2夜王生产者生产异鬼,目前共有2
Thread-1守夜人消费者杀异鬼,目前共有1
Thread-5守夜人消费者杀异鬼,目前共有0
Thread-4夜王生产者生产异鬼,目前共有1
Thread-0夜王生产者生产异鬼,目前共有2
Thread-5守夜人消费者杀异鬼,目前共有1
Thread-1守夜人消费者杀异鬼,目前共有0
Thread-2夜王生产者生产异鬼,目前共有1
Thread-3守夜人消费者杀异鬼,目前共有0