【发布时间】:2025-12-04 13:10:01
【问题描述】:
我有以下非常简单的回调接口和一个 POJO 类:
public interface Action{
public void doAction();
}
public class Person{
private String name;
private String address;
//...etc
//GET, SET, toString
}
我将按如下方式使用它:
public class ActionExecutor{
private static final Logger logger = LogManager.getLogger(ActionExecutor.class);
private final BlockingQueue<Action> blockingQueue = new LinkedBlockingQueue(2000);
public void execute(final Person p){
//modify state of p in some way
blockingQueue.put(new Action(){
public void doAction(){
logger.info("Execution started: " +p.toString );
//do some other job
});
}
}
BlockingQueue这里用来实现生产者-消费者。
问题: 是否保证从BlockingQueue 执行操作的消费者线程将写入正确的日志消息? IE。它观察到Person 的正确状态?但我并不确定。
我认为不,这不能保证,因为在生产者进行的修改和生产者阅读之间没有顺序之前发生。
【问题讨论】:
-
不,不保证。在调用 doAction 方法之前,Person p 的状态可能会改变。您可以获取 p.toString() 的字符串并将该字符串传递给您的 Action 构造函数并将其存储为 Action 实例的成员。
-
@bhspencer 所以我们只能安全地发布线程安全对象?
-
我不知道你在这里发布是什么意思。我认为问题不在于线程安全,而在于状态。当您将 Action 放入队列时,它所引用的 Person 并未处于锁定状态,因此当您的操作最终运行时,此人的状态可能与您创建 Action 时的状态不同。人 p 很可能是线程安全的,但如果它是可变的,它的状态可以在你的控制下改变。
-
也许你应该编写一个方法来克隆你的 Person 并将克隆的实例传递给你的 Action 构造。
-
如果多个线程可能会更改队列中对象的状态,则您无法知道它的状态。阻塞队列的“阻塞”功能只适用于将引用加载到队列中。
标签: java multithreading blockingqueue