多线程通信,使用notifyAll将所有在wait set中的阻塞线程全部唤醒,然后所有被唤醒的线程重新抢monitor锁,特别注意的地方,就是不能使用if判断队列是否满了或者为空(大小为0),如果使用if进行判断,线程直接从wait方法之后开始执行,这样就不会再判断是否满足条件,这样造成空指针,或者其它严重情况。因此,在多线程中使用while作为判断条件。
1、Order
package com.dl.cn;
/**
* 订单类
* Created by Tiger on 2018/8/13.
*/
public class Order {
//订单号
private int id;
public Order(int id){
this.id = id;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
2、OrderProcess
package com.dl.cn;
import java.util.LinkedList;
/**
* Created by Tiger on 2018/8/13.
*/
public class OrderProcess {
//最大存放订单的数量
private static final int MAX_ORDER_NUM = 5;
//存放订单数据
private static final LinkedList list = new LinkedList();
/**
* 添加订单到list
* */
public void addOrder(Order order){
synchronized (list){
while (list.size() >= MAX_ORDER_NUM){
try {
System.out.println("订单:"+order.getId()+","+"阻塞了-------");
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
//将订单添加到list集合
list.addLast(order);
System.out.println("订单:"+order.getId()+","+"订单已提交了============");
list.notifyAll();
}
}
/**
* 从list取订单进行处理
* */
public void getOrder(){
synchronized(list){
while (list.isEmpty()){
try {
System.out.println("暂时无订单");
list.wait();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
/**
* 取出订单,并进行处理,最后移除当前订单
* */
Order order = (Order) list.getFirst();
list.remove(order);
System.out.println("从list取订单"+order.getId()+"成功!");
list.notifyAll();
}
}
}
3、OrderMain
package com.dl.cn;
import java.util.concurrent.TimeUnit;
/**
* Created by Tiger on 2018/8/13.
*/
public class OrderMain {
public static void main(String[] args) {
final OrderProcess orderProcess = new OrderProcess();
/**
* 生产者1
* */
new Thread(new Runnable() {
@Override
public void run() {
int i = 1;
while (true){
try {
orderProcess.addOrder(new Order(i++));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}).start();
/**
* 生产者2
* */
new Thread(new Runnable() {
@Override
public void run() {
int i = 1000;
while (true){
try {
orderProcess.addOrder(new Order(i++));
} catch (Exception e) {
e.printStackTrace();
}
}
}
}).start();
/**
* 消费
* */
new Thread(new Runnable() {
@Override
public void run() {
while (true){
try {
orderProcess.getOrder();
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}
}
4、测试结果
E:\jdk18\bin\java -Didea.launcher.port=7532 "-Didea.launcher.bin.path=E:\interllijidea\IntelliJ IDEA\bin" -Dfile.encoding=UTF-8 -classpath "E:\jdk18\jre\lib\charsets.jar;E:\jdk18\jre\lib\deploy.jar;E:\jdk18\jre\lib\ext\access-bridge-64.jar;E:\jdk18\jre\lib\ext\cldrdata.jar;E:\jdk18\jre\lib\ext\dnsns.jar;E:\jdk18\jre\lib\ext\jaccess.jar;E:\jdk18\jre\lib\ext\jfxrt.jar;E:\jdk18\jre\lib\ext\localedata.jar;E:\jdk18\jre\lib\ext\nashorn.jar;E:\jdk18\jre\lib\ext\sunec.jar;E:\jdk18\jre\lib\ext\sunjce_provider.jar;E:\jdk18\jre\lib\ext\sunmscapi.jar;E:\jdk18\jre\lib\ext\sunpkcs11.jar;E:\jdk18\jre\lib\ext\zipfs.jar;E:\jdk18\jre\lib\javaws.jar;E:\jdk18\jre\lib\jce.jar;E:\jdk18\jre\lib\jfr.jar;E:\jdk18\jre\lib\jfxswt.jar;E:\jdk18\jre\lib\jsse.jar;E:\jdk18\jre\lib\management-agent.jar;E:\jdk18\jre\lib\plugin.jar;E:\jdk18\jre\lib\resources.jar;E:\jdk18\jre\lib\rt.jar;F:\ideaWorkSpace\practice\threadDemo\target\classes;E:\interllijidea\IntelliJ IDEA\lib\idea_rt.jar" com.intellij.rt.execution.application.AppMain com.dl.cn.OrderMain
订单:1000,订单已提交了============
订单:1001,订单已提交了============
订单:1002,订单已提交了============
订单:1003,订单已提交了============
订单:1004,订单已提交了============
订单:1005,阻塞了-------
订单:1,阻塞了-------
从list取订单1000成功!
订单:1,订单已提交了============
订单:2,阻塞了-------
订单:1005,阻塞了-------
从list取订单1001成功!
订单:1005,订单已提交了============
订单:1006,阻塞了-------
订单:2,阻塞了-------
从list取订单1002成功!
订单:2,订单已提交了============
订单:3,阻塞了-------
订单:1006,阻塞了-------
从list取订单1003成功!
订单:1006,订单已提交了============
订单:1007,阻塞了-------
订单:3,阻塞了-------
Process finished with exit code -1