最轻量线程安全消息队列用LinkedList+wait()/notify()实现,需while循环等待、add后notify、消息体预留type/priority/expireAt等字段,文件持久化用Files.write或PrintWriter,启动用CountDownLatch控制顺序。
用 wait() + notify() 实现线程安全的消息队列
Java里最轻量、不依赖第三方库的消息提醒系统,核心是让生产者(发消息)和消费者(处理提醒)解耦。直接用 LinkedList 配合 synchronized 块 + wait()/notify() 是最可控的做法——比裸用 BlockingQueue 更利于理解阻塞逻辑,也比自己加 Thread.sleep() 轮询更省资源。
常见错误是忘了在 while (queue.isEmpty()) 里等待,写成 if 导致虚假唤醒后直接 poll() 出 null;还有忘记在 addMessage() 末尾调用 notify(),导致消费者永远卡住。
-
getMessage()方法必须用while判断空队列,不能用if - 每次
addMessage()后必须notify(),哪怕队列没满也要唤醒等待中的消费者 - 不要在
wait()外层加try-catch InterruptedException后吞掉异常——应向上抛或重新设置中断状态
消息体设计要预留扩展字段,别只存 content 和 receiver
实际项目中,“提醒”不是只有“发给谁+说什么”。比如你要支持邮件、短信、站内信混合推送,就得在 Message 类里提前留好 type("email"/"sms")、priority(int)、expireAt(long 时间戳),甚至 retryCount。否则后期加字段要改所有生产者代码,还容易漏初始化。
一个典型坑是把接收者写成 String receiver,结果业务要求支持群发(多个邮箱)、分级通知(先发组长再发总监)。不如一开始定义为 List recipients,哪怕初期只加一个元素。
立即学习“Java免费学习笔记(深入)”;
- 加
timestamp字段,方便后续做延迟提醒或去重判断 - 避免用
public成员变量,getter/setter 虽啰嗦,但未来加校验逻辑(如邮箱格式检查)不用动调用方 - 如果消息可能持久化到文件,字段类型优先选
String、long、int,少用Date或自定义对象,减少序列化麻烦
文件落盘做兜底时,别用 FileWriter 直接追加
消息提醒系统一旦挂掉,内存里的队列就丢了。加文件持久化是刚需,但很多人用 FileWriter("queue.log", true) 每次写一条,结果高并发下日志错乱、换行丢失、甚至覆盖前一条——因为 FileWriter 不保证原子写入,也没缓冲区控制。