我有一个Results对象,由多个线程同时写入.但是,每个线程都有特定的用途并拥有某些字段,因此多个线程实际上不会修改任何数据.在完成所有写入线程的写入之前,此数据的使用者不会尝试读取它.因为我知道这是真的,所以数据写入和读取没有同步.
有一个与此Results对象关联的RunningState对象,用于协调此工作.它的所有方法都是同步的.当一个线程完成它对这个Results对象的工作时,它会调用RunningState对象上的done(),它执行以下操作:递减计数器,检查计数器是否已经变为0(表示所有写入器都已完成),以及如果是这样,将此对象放在并发队列上.该队列由ResultsStore使用,该结果读取所有字段并将数据存储在数据库中.在读取任何数据之前,ResultsStore调用RunningState.finalizeResult(),它是一个空方法,其唯一目的是在RunningState对象上进行同步,以确保读者可以看到所有线程的写入.
以下是我的担忧:
1)我相信这将正常工作,但我觉得我违反了良好的设计原则,不同步对多个线程共享的对象的数据修改.但是,如果我要添加同步和/或拆分,以便每个线程只看到它负责的数据,它会使代码复杂化.修改这个区域的任何人都能更好地理解在任何情况下发生了什么,或者他们可能会破坏某些东西,所以从维护的角度来看,我认为更简单的代码以及解释其工作原理的好评论是一种更好的方法.
2)我需要调用这种无操作方法的事实似乎表明错误的设计.是吗?
意见表示赞赏.
解决方法:
您的设计是合理的,但如果您使用真正的并发队列,则可以改进它,因为来自java.util.concurrent包的并发队列已经确保在将项目放入队列的线程与线程获取之间发生关系一个项目输出,所以这排除了需要在获取线程中调用finalizeResult()(因此不需要那个“什么都不做”的方法调用).
来自java.util.concurrent包描述:
The methods of all classes in java.util.concurrent and its subpackages
extend these guarantees to higher-level synchronization. In
particular:
- Actions in a thread prior to placing an object into any
concurrent collection happen-before actions subsequent to the access
or removal of that element from the collection in another thread.
关于使用AtomicInteger而不是同步的另一个答案中的注释也是明智的(因为使用AtomicInteger进行线程计数可能比同步更好),只需确保在原子减量后得到计数值(例如decrementAndGet) ())与0比较时为了避免两次加入队列.