2

我的应用程序包含许多包含 getter 和 setter 的对象。这些对应于改变物理对象(例如,步进电机)的状态。其他线程可能会调用此对象上的方法以对步进电机执行操作——这提供了步进电机和底层硬件之间的接口。因此,例如,我们可能有一个使电机旋转 15 度的函数,或者我们可能有一个使其返回中性位置的函数。

现在,这些对象关心线程安全,但这还不够好。考虑这样一种情况:一个线程尝试将电机旋转 90 度(通过触发六个调用旋转 15 度)并且在中途,另一个线程重置电机,这意味着它只移动了 45 度。

我的设计解决方案是允许控制对象取出控制器上的锁,但我不确定如何管理它。似乎大多数 Java 锁定方法都设计为在单个方法调用上是原子的,我希望将对象锁定一段不确定的时间。

一个简单的 Java 锁是否足以达到此目的,或者有人知道更好的东西吗?我担心标准的 ReentrantLock 似乎几乎需要 try-finally 范式,这意味着我可能会在一定程度上对它进行贬低。

4

2 回答 2

1

您可以提供一种以原子方式提交多个命令的方法。假设你所有的方法都是同步的,它可能只是:

public synchronized void submitAtomically(List<Command> commands) {
    for (Command c : commands) {
        submit(c);
    }
}

public synchronized void submit(Command c) {
    //rotate or reset or ...
}

如果您不希望这些方法阻塞其他线程太久,最简单的方法是使用典型的生产者/消费者模式:

private final BlockingQueue<Command> queue = new LinkedBlockingQueue<> ();

public synchronized void submit(Command c) {
    queue.put(c);
}    

//somewhere else:

new Thread(new Runnable() {
    public void run() {
        while(true) {
            Command c = queue.take();
            c.execute();
        }
    }
}).start();

如果客户端通过 提交 6 个轮换submitAtomically,它会阻止其他线程在 6 个轮换中间插入其他命令。但是submit操作非常快(它实际上并不执行命令),因此它不会长时间阻塞其他线程。

于 2013-08-14T11:48:35.687 回答
0

在数据库世界中,这是通过事务来完成的,这是一种将小的低级操作分组为原子的大的高级操作的方法。走那条路会很痛苦。

我认为你需要回过头来决定基本的原子操作是什么。

考虑这样一种情况:一个线程尝试将电机旋转 90 度(通过触发六个调用旋转 15 度)并且在中途,另一个线程重置电机,这意味着它只移动了 45 度。

您似乎已经决定“旋转 15 度”是唯一的原子操作,但这显然不适合您的应用程序。

  • 您是否还需要“旋转 45 度”和“旋转 90 度”作为原子操作?也许您需要“旋转X度”作为原子操作?

  • 将电机旋转到特定位置的目的是什么?如果线程A将电机旋转到位置X,然后线程B立即将其旋转到不同的位置,已经实现了什么?一旦电机位于位置X,是否需要执行一些操作(通过线程A ) ?如果是这样,您希望旋转该操作一起成为一个原子操作。

  • 为什么在执行操作之前将电机旋转给定的量?实际上,您是否希望电机在执行操作时处于特定位置(绝对位置,而不是相对于其先前位置)?在这种情况下,您不希望您的操作获得旋转的数量,而是所需的位置。原子操作将负责决定电机旋转多少。

于 2013-08-14T12:34:31.900 回答