Closed. This question needs to be more focused。它当前不接受答案。












想要改善这个问题吗?更新问题,使它仅关注editing this post的一个问题。

4年前关闭。



Improve this question




我正在寻找实现已记录日志或其中包含持久事务的对象。也就是说,对象包含数据(也许是Map)。在对数据进行更改时,这些更改将单独保存,并在需要时进行沙箱处理,以便任何外部对象都可以引用基本状态(更改之前)或访问最新数据。然后还有另一个操作将更改提交到基本状态。

它使我想起了Linux日记文件系统。文件系统更改将被写入日志,并且仅在以后提交到永久存储中。

它也可能与关系数据库世界中的“事务”概念更为相似。也就是说,您有一些数据,开始事务并以某种方式处理数据。并发进程将看到旧数据,而无需进行任何更改。然后,您可以“回滚”事务或“提交”更改。

我特别希望在Java中实现此功能,但是,即使它存在,显然它也是一种通用的面向对象模式。我希望至少可以创建它,但是我不太确定实现它的最佳方法。

同样,假设对象包含一整吨数据,整个层次结构(子对象等等)。因此,一个人不能只保留整个数据树的两个副本。这将非常浪费内存,并且复制操作(提交时)将花费太多时间。我希望在游戏的上下文中实现此功能,每帧执行一次提交操作,因此它确实需要是最佳的。

最佳答案

实现所需目标的最佳方法是使对象及其所有子对象不可变。这样,这两个线程就可以在它们上进行操作而不会发生任何冲突,并且您不必维护所有内容的两个副本。唯一需要两份副本的是实际更改的内容,这些内容可能很小。

假设对象A由对象B和C组成。对象B由对象D和E组成。对象C由对象F和G组成。因此,A,B和C分别只是两个指针,而D,E, F和G是它们的任何东西。

首先,您创建您的初始实例,并将其分配给两个线程。

ThreadOne -> A1{ B1{ D1, E1 } C1{ F1, G1 } }
ThreadTwo -> A1{ B1{ D1, E1 } C1{ F1, G1 } }

因此,两个线程都指向同一个实例,没有消耗额外的内存,也没有线程问题,因为对象永远不会改变。

现在,ThreadOne需要修改对象F。为此,它只需创建一个新的F,一个包含它的新C以及一个包含新C的新A。原始的B,D,E和G保持不变,并且不需要复制。
ThreadOne -> A2{ B1{ D1, E1 } C2{ F2, G1 } }
ThreadTwo -> A1{ B1{ D1, E1 } C1{ F1, G1 } }

这两个线程共享B,D,E和G的实例。

现在,ThreadOne需要修改对象E。
ThreadOne -> A3{ B2{ D1, E2 } C2{ F2, G1 } }
ThreadTwo -> A1{ B1{ D1, E1 } C1{ F1, G1 } }

现在ThreadTwo需要最新版本,因此ThreadOne只是为其提供了指向其副本的指针。
ThreadOne -> A3{ B2{ D1, E2 } C2{ F2, G1 } }
ThreadTwo -> A3{ B2{ D1, E2 } C2{ F2, G1 } }

由于对象是不可变的,因此没有任何线程问题的危险,并且ThreadOne可以继续进行更改,每次仅创建已更改的部件及其容器的新实例。
ThreadOne -> A4{ B3{ D2, E2 } C2{ F2, G1 } }
ThreadTwo -> A3{ B2{ D1, E2 } C2{ F2, G1 } }

ThreadOne -> A5{ B3{ D2, E2 } C3{ F3, G1 } }
ThreadTwo -> A3{ B2{ D1, E2 } C2{ F2, G1 } }

这是快速的,内存有效的和线程安全的。

10-04 16:50