RError.com

RError.com Logo RError.com Logo

RError.com Navigation

  • 主页

Mobile menu

Close
  • 主页
  • 系统&网络
    • 热门问题
    • 最新问题
    • 标签
  • Ubuntu
    • 热门问题
    • 最新问题
    • 标签
  • 帮助
主页 / 问题 / 985589
Accepted
ImmRaytal
ImmRaytal
Asked:2020-05-26 02:49:25 +0000 UTC2020-05-26 02:49:25 +0000 UTC 2020-05-26 02:49:25 +0000 UTC

同步的类似物

  • 772

有一个任务。有必要实现多线程应用程序,而不使用同步。

有一个带泊位的港口(1 个泊位 - 1 艘船)。有货船和仓库。在泊位,船舶可以将货物转移到仓库或另一艘船上。

我简单地尝试在每个函数中将 ReentrantLock 放在开头和结尾。显然我误解了它是如何工作的。使用同步,您可以简单地将它挂在第一次进入函数的每个线程上,并且一切正常,但没有它 - 死胡同。谁能建议如何正确使用锁或其他方式来实现这样的应用程序?

GitHub

一段代码:

private ReentrantLock lock = new ReentrantLock();

public boolean tryTransfer(Ship ship) {// ф-ия пытается добавить груз(cargo)  в хранилище
    boolean flag;                      // capacity - объём хранилища
    lock.lock();

    if (capacity + ship.getCargo()>maxCapacity) { 
        flag = false;
    } else
    {
        capacity+=ship.getCargo();
        ship.setCargo(0);

        flag = true;
    }
         lock.unlock();
        return flag;
}
java
  • 1 1 个回答
  • 10 Views

1 个回答

  • Voted
  1. Best Answer
    gamerforEA
    2020-05-26T19:22:45Z2020-05-26T19:22:45Z
    1. 您经常ReentrantLock在方法内创建并在同一个地方使用它们(这可以在类Dock和中看到Ship)。如果您不将这些锁传递给其他地方,那将没有任何意义。存储ReentrantLock在字段中。
    2. 您的实现Storage#tryTransfer(在 GitHub 上,不在此处)几乎是正确的。您正确地限制了对Storage. 但是,在此方法中,您无法正确使用Ship- 方法Ship#getCargo并且Ship#setCargo未同步。在这种情况下,您需要同时锁定Storage, 和Ship。像这样的东西(通过类比,你可以重做其他所有事情):

      public class Ship {
          private final ReentrantLock lock = new ReentrantLock();
          private double cargo;
      
          public double getCargo() {
              this.lock.lock();
              try {
                  return this.cargo;
              } finally {
                  this.lock.unlock();
              }
          }
      
          public void setCargo(double cargo) {
              this.lock.lock();
              try {
                  this.cargo = cargo;
              } finally {
                  this.lock.unlock();
              }
          }
      
          public ReentrantLock getLock() {
              return this.lock;
          }
      }
      
      public class Storage {
          private final ReentrantLock lock = new ReentrantLock();
          private final double maxCapacity = 100;
          private double capacity;
      
          public boolean tryTransfer(Ship ship) {
              this.lock.lock();
              try {
                  ship.getLock().lock();
                  try {
                      if (this.capacity + ship.getCargo() > this.maxCapacity) {
                          return false;
                      }
      
                      this.capacity += ship.getCargo();
                      ship.setCargo(0);
                  } finally {
                      ship.getLock().unlock();
                  }
      
                  return true;
              } catch (Exception e) {
                  e.printStackTrace();
              } finally {
                  this.lock.unlock();
              }
      
              return false;
          }
      }
      
    3. 如果第 2 点已经在and中,为什么Storage#tryTransfer我还要锁定它?事实上,当多个线程同时使用同一个实例时,这种情况是可能发生的。那些。例如,我们调用并接收到 10。我们希望当我们调用 时,cargo 仍然等于 10。但是,如果我们的调用之间没有额外的同步,并且某个其他线程本身可以使用其他值调用,我们得到 ,在我们打电话时,货物不是原来的 10,而是例如 12。Ship#getLockShip#getCargoShip#setCargoShipShip#getCargoShip.setCargo(0)Ship#getCargoShip#setCargoShip#setCargoShip#setCargo(0)

    更新

    1. 您在使用它时Ship#run忘记了锁Dock。
    2. 在Ship#run你调用ReentrantLock#lock里面try-finally,而不是在它之前。这是无法做到的,因为try-finally在获取锁之前它可能会被中断(例如,由于异常),但ReentrantLock#unlock它仍然会被调用。
    3. 你为什么Ship#run打电话Dock#setCurrentShip?直接放进去不就好Ship了Dock#shipsQueue,然后码头自己先搞清楚要处理哪艘船?
    4. Dock#run通话后ReentrantLock#lock立即做try-finally。正常情况下甚至会发生异常System.out.println(),导致您的异常ReentrantLock#unlock不会被调用。
    5. 如果您使用某些数据,请立即锁定。例如,在Dock#run您首先检查Dock#currentShip然后才取锁。情况并非总是如此。如果它Dock#currentShip没有突出,那么这将是正常的,但是你有Dock#getCurrentShipand Dock#setCurrentShip,这意味着需要同步它们。
    6. 纯架构缺陷:删除Dock#setShipsQueue. 不是任何人都可以拿走并替换如此重要的收藏品的情况。最好完全在内部创建它Dock(而不是从外部接受它)并且不要将其提供给任何人 - 只需添加 publicDock#addShip和Dock#removeShip. 好吧,Dock#isFree您可以对其进行修改,使其不返回某些字段的值,而是检查Dock#currentShip和Dock#shipsQueue(尽管您可以自己决定 - 我不知道您的原始想法)。
    7. Dock#isFree将始终false在第一次处理任何非空船后返回。在我看来,这里出了点问题——船总有一天会用完=>在这种情况下,码头应该是空的,这不会发生。

    更新

    1. ReentrantLock#unlock您无需在调用之前先调用ReentrantLock#tryLock。线程已经拥有锁,所以这个检查不会做任何事情。
    2. 在Ship#run您的队列中,您可以无休止地添加一艘船。只需删除循环,您不需要它。
    3. 新的实现Storage#run是完全不正确的。即使您省略了第 1 点,出于某种原因,您也会在之前return和类似的运算符之前释放锁。没有必要这样做 - 块finally总是被执行,即使在returnor之后也是如此continue。
    4. 您在之前的答案更新中遗漏了第 5 点。
    • 2

相关问题

Sidebar

Stats

  • 问题 10021
  • Answers 30001
  • 最佳答案 8000
  • 用户 6900
  • 常问
  • 回答
  • Marko Smith

    根据浏览器窗口的大小调整背景图案的大小

    • 2 个回答
  • Marko Smith

    理解for循环的执行逻辑

    • 1 个回答
  • Marko Smith

    复制动态数组时出错(C++)

    • 1 个回答
  • Marko Smith

    Or and If,elif,else 构造[重复]

    • 1 个回答
  • Marko Smith

    如何构建支持 x64 的 APK

    • 1 个回答
  • Marko Smith

    如何使按钮的输入宽度?

    • 2 个回答
  • Marko Smith

    如何显示对象变量的名称?

    • 3 个回答
  • Marko Smith

    如何循环一个函数?

    • 1 个回答
  • Marko Smith

    LOWORD 宏有什么作用?

    • 2 个回答
  • Marko Smith

    从字符串的开头删除直到并包括一个字符

    • 2 个回答
  • Martin Hope
    Alexandr_TT 2020年新年大赛! 2020-12-20 18:20:21 +0000 UTC
  • Martin Hope
    Alexandr_TT 圣诞树动画 2020-12-23 00:38:08 +0000 UTC
  • Martin Hope
    Air 究竟是什么标识了网站访问者? 2020-11-03 15:49:20 +0000 UTC
  • Martin Hope
    Qwertiy 号码显示 9223372036854775807 2020-07-11 18:16:49 +0000 UTC
  • Martin Hope
    user216109 如何为黑客设下陷阱,或充分击退攻击? 2020-05-10 02:22:52 +0000 UTC
  • Martin Hope
    Qwertiy 并变成3个无穷大 2020-11-06 07:15:57 +0000 UTC
  • Martin Hope
    koks_rs 什么是样板代码? 2020-10-27 15:43:19 +0000 UTC
  • Martin Hope
    Sirop4ik 向 git 提交发布的正确方法是什么? 2020-10-05 00:02:00 +0000 UTC
  • Martin Hope
    faoxis 为什么在这么多示例中函数都称为 foo? 2020-08-15 04:42:49 +0000 UTC
  • Martin Hope
    Pavel Mayorov 如何从事件或回调函数中返回值?或者至少等他们完成。 2020-08-11 16:49:28 +0000 UTC

热门标签

javascript python java php c# c++ html android jquery mysql

Explore

  • 主页
  • 问题
    • 热门问题
    • 最新问题
  • 标签
  • 帮助

Footer

RError.com

关于我们

  • 关于我们
  • 联系我们

Legal Stuff

  • Privacy Policy

帮助

© 2023 RError.com All Rights Reserve   沪ICP备12040472号-5