
本文解释为何 Q 类中 Thread.currentThread() 在对象初始化时被错误捕获为 main 线程,导致 put() 和 get() 日志始终显示“main thread”;并提供简洁可靠的修复方案——改用 Thread.currentThread().getName() 动态获取调用线程名。
本文解释为何 `q` 类中 `thread.currentthread()` 在对象初始化时被错误捕获为 `main` 线程,导致 `put()` 和 `get()` 日志始终显示“main thread”;并提供简洁可靠的修复方案——改用 `thread.currentthread().getname()` 动态获取调用线程名。
问题根源在于 Q 类中这一行代码:
Thread t = Thread.currentThread();
它在 Q 实例构造时(即 new Q() 被调用时)执行,而此时 main 方法正运行在主线程中,因此 t 永远指向 main 线程 —— 无论后续是 Producer1 还是 Consumer1 调用 put() 或 get(),打印的始终是这个初始化时快照的线程引用,而非实际执行方法的线程。
✅ 正确做法:每次需要线程名时,动态获取当前执行线程。只需两步修改:
- 删除 Q 类中冗余的 Thread t 字段;
- 将所有 t.getName() 替换为 Thread.currentThread().getName()。
修改后的 Q 类关键部分如下(仅展示改动处):
public class Q {
boolean ready = false;
List<Integer> products;
Q() {
products = new ArrayList<>(5);
}
synchronized void put(int n) {
while (ready) {
try {
wait();
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName() + " was interrupted!");
System.out.println(e);
}
}
if (products.size() < 5) {
products.add(n);
System.out.println(Thread.currentThread().getName() + ", Put: " + n); // ✅ 动态获取
ready = true;
notify();
} else {
System.out.println(Thread.currentThread().getName() + ", List is full!");
ready = true;
notify();
}
}
synchronized List<Integer> get() {
while (!ready) {
try {
wait();
} catch (InterruptedException e) {
System.out.println(Thread.currentThread().getName() + " was interrupted!");
System.out.println(e);
}
}
if (products.size() > 1) {
System.out.println(Thread.currentThread().getName() + ", Got: " + products);
System.out.println(Thread.currentThread().getName() + ", Consumed: \"" + products.get(products.size() - 1) + "\"");
removeLastElement();
ready = false;
notify();
} else {
System.out.println(Thread.currentThread().getName() + ", List is empty!");
ready = false;
notify();
}
return products;
}
void removeLastElement() {
if (!products.isEmpty()) {
products.remove(products.size() - 1);
}
}
}⚠️ 注意事项:
- 不要尝试在 Q 中缓存 Thread 引用(如字段或局部变量),除非明确需要绑定到特定上下文(本例完全不需要);
- Thread.currentThread() 是轻量级、线程安全的静态方法,无性能顾虑,适合高频日志场景;
- 确保 Producer 和 Consumer 的 Thread 对象已通过带 name 参数的构造器正确命名(您的代码已满足:new Thread(this, threadName)),这是 getName() 返回预期名称的前提;
- 补充建议:get() 方法中 products.size() > 1 的判断逻辑存在语义偏差(应为 > 0 才能消费单个元素),且 removeLastElement() 缺少空检查,已在上方示例中一并优化。
修复后,控制台将按预期输出:
Producer1, Put: 0 Consumer1, List is empty! Producer1, Put: 1 Consumer1, Got: [0, 1] Consumer1, Consumed: "1"
这不仅解决了线程名显示问题,更强化了对“线程上下文”的正确认知:线程身份属于执行动作的瞬间,而非对象创建的时刻。

















