0

对于大学作业,我需要实现医院患者等待系统的一部分。该系统使用等待名单上的患者集合,以及在特定时期(例如今年)注册手术的一组患者。

我已经使用 HashSet 和 LinkedList 实现了如下所需的方法。该方法几乎是完全同步的,所以我想知道是否有更有效的实现更少的同步,或者更细粒度的读写同步使用锁?

public Class OperationPeriod {
...
private Set<Patient> registeredPatients=new HashSet<Patient>();
private Collection<Patient> waitingListPatients=new LinkedList<Patient>();
    private int capacity;
...

    public boolean bookOperation(Patient patient){
    if (!Operation.checkHasMetRequirements(patient)) {
        return false;
    }

    //patient could already be registered
    synchronized(this) {
        if(registeredPatients.contains(patient)) {
            return true;
        }
        if(waitingListPatients.contains(patient) ) {
            return false;
        }
        //Not already registered so register or add to waiting list
        return addPatient(patient);
    }
}

private boolean addPatient(Patient patient) {
    if(registeredPatients.size() < capacity) {
        registeredPatients.add(patient);
        return true;
    }
    else {
        waitingListPatients.add(patient);
        return false;
    }
}
4

3 回答 3

1

您在这里只有一些代码,但您的同步看起来不错。

仅供参考,你的LinkedList.contains需要O(n)。我会做以下其中一项

  1. 使用LinkedHashSet具有持续查找但保持顺序的 a 。但是,根据您以后对它的使用,这可能并不令人满意。

  2. 使用 aHashSet来增加您的LinkedList. 检查时使用LinkedListexcept .contains()

于 2013-11-13T02:31:33.173 回答
1

您可以考虑读/写锁......但选择它取决于您对用户只阅读集合的频率的期望,而不是阅读和写作。

A. 用户尝试添加已经存在的患者多少次(阅读)

B. 您多久会从应用程序的其他部分读取列表(读取)

C. 用户成功添加患者的次数(读+写)

如果 (A + B) 与 C 相比很大,请考虑像java.util.concurrent.locks.ReentrantReadWriteLock. 调用 readLock() 开始你的阅读(它只会阻塞写者,而不是其他读者),如果有必要,释放读锁并调用 writeLock() 升级为写(从而阻塞所有其他的读写)。获得写锁后,请务必重新检查您在读锁阶段检查的断言。

除此之外,您现有的同步看起来不错。

于 2013-11-13T02:37:20.747 回答
0

一个想法是ReadWriteLock。因为在这部分代码中:

synchronized(this) {
  if(registeredPatients.contains(patient)) {
    return true;
  }
  if(waitingListPatients.contains(patient) ) {
    return false;
  }
  //Not already registered so register or add to waiting list
  return addPatient(patient);
}

您正在阻止对整个列表的访问,即使只是在列表上读取不会导致任何线程问题,但是您需要锁定以防指令稍后可以写入。这是由 ReadWriteLock 解决的,通过授予无限制的读取访问权限,除非有人真正想要写入。这可以这样实现:

lock.readLock().lock();
try {
  if(registeredPatients.contains(patient)) {
    return true;
  }
  if(waitingListPatients.contains(patient) ) {
    return false;
  }
} finally {
  lock.readLock().unlock();
}

//Not already registered so register or add to waiting list
lock.writeLock().lock();
try {
  // need to re-check here, as the list could have been changed in between
  if(registeredPatients.contains(patient)) {
    return true;
  }
  if(waitingListPatients.contains(patient) ) {
    return false;
  }
  return addPatient(patient);
} finally {
  lock.writeLock().unlock();
}

现在,如果许多线程只需要读取,但很少写入,这将提高您的应用程序的速度。如果几乎所有读取以及写入的线程,这实际上会减慢速度,因为您不仅需要检查两次,还需要锁定两次。另外同步比锁快。

于 2013-11-14T14:02:47.770 回答