1. 使用注意事项
- 只能在synchronized关键字中调用 wait()方法、notify()系列方法
- 尽可能用 notifyall(),因notify()只能唤醒一个线程,不确定是哪一个线程
2. 示例
2.1 生产者
private Integer zd = 0; // 定义子弹变量
// 生产者生产子弹
public synchronized void set(){
while ( zd >= 20 ) {
try {
System.out.println(Thread.currentThread().getName() + "子弹已经装满了");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
zd++;
System.out.println(Thread.currentThread().getName() + " 装入子弹一枚");
// 唤醒所有在wait状态的线程,可能消费者也处于wait状态,唤醒,进行消费子弹
notifyAll();
}
// 生产者线程生产子弹
public static class producer implements Runnable{
Task task;
public producer(Task task) {
this.task = task;
}
@Override
public void run() {
// do my work
while (true) {
// 生产者一直去调用set,生产子弹
task.set();
try {
Thread.sleep(6);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
2.2 消费者
private Integer zd = 0; // 定义子弹变量
// 消费者消费子弹
public synchronized void get(){
while ( zd <= 0 ) {
try {
System.out.println(Thread.currentThread().getName() + " 子弹已经射完了" );
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
zd--;
System.out.println(Thread.currentThread().getName() + " 发射一枚子弹" );
// 唤醒所有在wait状态的线程,可能生产者也处于wait状态,唤醒,进行生产子弹
notifyAll();
}
// 消费者线程消费子弹
public static class consumer implements Runnable{
Task task;
public consumer(Task task) {
this.task = task;
}
@Override
public void run() {
// do my work
while (true) {
// 消费者一直去调用get,消费子弹
task.get();
try {
Thread.sleep(6);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
2.3 启动类
public static void main(String[] args) {
Task task = new Task();
// 开启10个生产者线程
for (int i = 0; i < 10; i++) {
new Thread(new producer(task), "生产者: " + i).start();
}
// 开启10个消费者线程
for (int i = 0; i < 10; i++) {
new Thread(new consumer(task), "消费者: " + i).start();
}
}
3. 完整代码
public class Task {
/*
分析:
生产者需要检测枪膛是不是还有子弹,如果子弹不满,则添加子弹(子弹+1), 需要唤醒处于wait状态的消费者,进行消费子弹,如果子弹满了,则等待子弹的消耗(子弹-1)
消费者需要检测枪膛是不是还有子弹,如果有子弹,则使用子弹(子弹-1),需要唤醒处于wait状态的生产者,进行生产子弹,如果没有子弹,则等待子弹的添加(子弹+1)
*/
private Integer zd = 0; // 定义子弹变量
// 消费者消费子弹
public synchronized void get(){
while ( zd <= 0 ) {
try {
System.out.println(Thread.currentThread().getName() + " 子弹已经射完了");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
zd--;
System.out.println(Thread.currentThread().getName() + " 发射一枚子弹");
// 唤醒所有在wait状态的线程,可能生产者也处于wait状态,唤醒,进行生产子弹
notifyAll();
}
// 生产者生产子弹
public synchronized void set(){
while ( zd >= 20 ) {
try {
System.out.println(Thread.currentThread().getName() + " 子弹已经装满了");
wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
zd++;
System.out.println(Thread.currentThread().getName() + " 装入子弹一枚" );
// 唤醒所有在wait状态的线程,可能消费者也处于wait状态,唤醒,进行消费子弹
notifyAll();
}
// 消费者线程消费子弹
public static class consumer implements Runnable{
Task task;
public consumer(Task task) {
this.task = task;
}
@Override
public void run() {
// do my work
while (true) {
// 消费者一直去调用get,消费子弹
task.get();
try {
Thread.sleep(6);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
// 生产者线程生产子弹
public static class producer implements Runnable{
Task task;
public producer(Task task) {
this.task = task;
}
@Override
public void run() {
// do my work
while (true) {
// 生产者一直去调用set,生产子弹
task.set();
try {
Thread.sleep(6);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}
// 入口函数
public static void main(String[] args) {
Task task = new Task();
// 开启10个生产者线程
for (int i = 0; i < 10; i++) {
new Thread(new producer(task), "生产者: " + i).start();
}
// 开启10个消费者线程
for (int i = 0; i < 10; i++) {
new Thread(new consumer(task), "消费者: " + i).start();
}
}
}