Java 简单的LinkedList和队列同步
对于大学作业,我需要实施医院患者等待系统的一部分。该系统使用等待名单上的患者集合,以及在指定期间(例如今年)注册手术的一组患者 我使用HashSet和LinkedList实现了如下所需的方法。该方法几乎是完全同步的,所以我想知道是否有一种更有效的实现,使用更少的同步,或者使用锁进行更细粒度的读写同步Java 简单的LinkedList和队列同步,java,multithreading,concurrency,Java,Multithreading,Concurrency,对于大学作业,我需要实施医院患者等待系统的一部分。该系统使用等待名单上的患者集合,以及在指定期间(例如今年)注册手术的一组患者 我使用HashSet和LinkedList实现了如下所需的方法。该方法几乎是完全同步的,所以我想知道是否有一种更有效的实现,使用更少的同步,或者使用锁进行更细粒度的读写同步 public Class OperationPeriod { ... private Set<Patient> registeredPatients=new HashSet<Pat
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;
}
}
公共类操作周期{
...
private Set registeredPatients=new HashSet();
私有集合waitingListPatients=new LinkedList();
私人int能力;
...
公共布尔bookOperation(患者){
如果(!手术检查测量要求(患者)){
返回false;
}
//病人可能已经登记了
已同步(此){
if(注册患者。包含(患者)){
返回true;
}
if(waitingListPatients.contains(患者)){
返回false;
}
//尚未注册,因此请注册或添加到等待列表中
返回患者(患者);
}
}
私人病人(病人){
if(registeredPatients.size()<容量){
登记患者。添加(患者);
返回true;
}
否则{
waitingListPatients.add(患者);
返回false;
}
}
此处只有部分代码,但同步效果良好
仅供参考,您的链接列表。包含获取O(n)
。我将执行以下操作之一
使用一个LinkedHashSet
,它具有不断的查找功能,但可以保持顺序。但是,根据您以后的使用情况,这可能并不令人满意
使用HashSet
来扩充您的LinkedList
。使用LinkedList
除非选中.contains()
你可以考虑读/写锁……但是选择它取决于你对用户将只阅读集合的次数的期望,而不是读和写。
A.用户尝试添加已存在患者的次数(读取)
B.您从上面未显示的应用程序的另一部分读取列表的频率(阅读)
C.用户成功添加患者的次数(读+写)
如果(A+B)与C相比是巨大的,那么考虑一个读/写锁,比如“代码> java .UTI.O.Out.Cord.ReEntReTrAdRead Loope< /COD>。(从而阻止所有其他读写操作)。获得写锁后,请确保重新检查在读锁阶段检查的断言
除此之外,您现有的同步看起来还不错。一个想法是读写锁。因为在这部分代码中:
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();
}
现在,如果许多线程只需要读取,而很少写入,这将提高应用程序的速度。如果几乎所有读取和写入的线程都需要写入,这实际上会降低速度,因为您不仅需要检查两次,还需要锁定两次。此外,同步比锁定快。LinkedHashSet是一个非常好的idea、 感谢您指出这一点。它还提供了持续删除功能,这在取消患者预约时非常有用。为什么您说它可能不适合其他用途?您的意思是队列是否需要按照与插入顺序不同的顺序进行排序,例如自然顺序?或者如果我希望重新插入一个元素(无需删除和重新插入)在队列中的稍后点?@user2977365,如果您打算将其用作FIFO队列,它将非常有效(创建迭代器,调用next
,然后调用remove
)。如果您需要LinkedList的所有功能,如FILO队列,那么它不是一个好的选择。读/写锁只有在读比写多得多的情况下才真正有用。这就是为什么Java的同步集合不使用它们()我认为这是一个很好的解释。感谢您的澄清,我认为这是事实,但对实施不完全有信心。就目前而言,在我的应用程序(a+B)中