简体   繁体   中英

Simple LinkedList and Queue synchronization

For a college Assignment I need to implement part of a hospital patient waiting system.The system uses a Collection of Patients on a waiting list, and a set of Patients registered for an operation during a specified period, for example this year.

I have implemented the method required as below, using a HashSet and a LinkedList. The method is almost completely synchronized, so I am wondering if there is a more efficient implementation with less synchronization, or perhaps more granular read write synchronization using locks?

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;
    }
}

You only have some of your code here, but your synchronization looks good.

FYI, your LinkedList.contains takes O(n) . I would do one of the following

  1. Use a LinkedHashSet which has constant lookup, but maintains the order. However, depending on your use of this later, this might not be satisfactory.

  2. Use a HashSet to augment your LinkedList . Use the LinkedList except when checking .contains() .

You could consider a read/write lock... but choosing that depends on your expectations of how often users will be only reading the collections, versus reading and writing.

A. How many times users try to add a patient that already exists (read)

B. How often you'll be reading the lists from another part of your application not shown above (read)

C. How many times users successfully add a patient (read + write)

If (A + B) is huge when compared to C, consider a read/write lock like java.util.concurrent.locks.ReentrantReadWriteLock . Call readLock() to start your reading (which only blocks writers, not other readers), and if necessary, release the read lock and call writeLock() to escalate to writing (thereby blocking all other reads and writes). After obtaining the write lock, be sure to re-check your assertions you checked during the read-lock stage.

That aside, your existing synchronization looks fine.

One idea would be a ReadWriteLock. Because in this part of the code:

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);
}

you are blocking access to the entire list, even though just reading on the list wouldn't cause any threading issues, but then you need to lock just in case the instruction could write later on. This is solved by the ReadWriteLock, by granting unlimited read access unless someone actually wants to write. This could be implemented like this:

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();
}

Now if many threads only need to read, but rarely write, this will increase the speed of your application. If almost all threads that read as well write, this would actually slow things down, as you not only need to check twice, but as well need to lock twice. In addition synchronized is faster than lock.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM