挑剔的主人(锁?)

时间:2013-12-25 17:19:30

标签: java multithreading wait synchronized notify

我相信无论使用何种语言都可以考虑我的问题但是,为了获得一些'锚',我将使用Java语言对其进行描述。

让我们考虑以下场景: 我有一个 PickyHost 类扩展了Thread及其实例, pickyHostInst 正在运行。 该课程可能如下所示:

class PickyHost extends Thread {
    private ArrayList<Guest> guests;
    public void enter(Guest g) {
        // deal with g
    }
    private void pickGuests() {
        // ...
    }
    public void run() {
        // listen indefinitely
    }
}

此外,在后台,我有很多来宾实例正在运行(他们还扩展主题类),偶尔会有一些来宾想要在 pickyHostInst 上使用参数 g 调用输入方法。 现在,我希望 PickyHost 在以下意义上挑剔:

在某人调用输入方法后,会立即将 g 放在来宾列表的末尾,并强制 g 等待通知。另外(我认为这里存在问题的关键)它会自行进行5秒钟的睡眠,并以某种方式允许(在这5秒内)其他客人调用输入方法(如果发生这种情况,那么它会忘记)关于它需要多长时间睡眠并重置其闹钟再睡5秒钟 - 我称之为敏感睡眠

正如你所看到的,如果很多客人到达, pickyHostInst 睡觉的总时间可能很长 - 例如:A到达,然后4秒后B到达,然后又过了4秒C到达并且等等。然而,假设已经创建了A,B,......,G的链,从G到达的那一刻到5秒之后,没有人到达。 然后我希望 pickyHostInst 调用 pickGuests 方法,该方法使用某种算法确定{A,B,...,G的子集 S客人通知他们可以停止等待并继续他们通常做的事情,而且从来宾列表中删除S的元素。方法 pickGuests 可能需要一些时间才能完成,同时一些客人H可能已到达并调用输入 - 然后输入应正常进行但< strong> pickGuests 应该忽略H并且在它与{A,B,...,G}的最后一次调用处理结束时 - 而不是{A,B,...,G,H}。 完成 pickGuests 之后, pickyHostInst 应该(这里我有2个想法 - 实施其中任何一个都会让我开心:)) 任

  1. 再次进入5秒敏感睡眠之后,如果H到达后没有来宾,再次调用 pickGuests
  2. 同时通过输入方法为客人提供服务但仅在调用 pickGuests 之后 max(“来自S的最后一位客人(来自上次调用)的时刻通知 pickyHostInst (例如:S中的最后一位”谢谢你,主持人“)”,“片刻后5秒最后(最新)访客调用输入“)。
  3. 最后,经过长时间的介绍,我的问题 - 我需要哪些工具来完成这样的任务?不幸的是,我在各种锁和多线程/锁定机制的丰富性中有点迷失,并且无法辨别哪一个适合我的问题(或哪些,以某种方式结合)。

    我将非常感谢一些能让我走上正轨的代码草图。

2 个答案:

答案 0 :(得分:1)

您可以使用java.util.Timer对象,可以使用enter方法重置该对象。计时器任务将在其自己的线程中运行,如果未事先取消,则为您进行拣选。

请注意,enter方法将在众多Guest个线程之一上运行。这意味着它可能应该同步。最简单的方法是将synchronized关键字添加到Java中的方法声明:public synchronized void enter(Guest g)。这将确保一次只能有一位客人进入。您可以将计时器取消/重启代码放在此处。

java.util.Timer通过抽象java.util.TimerTask类的方式。这是一种Runnable类型,它还有一种取消任务的方法。我的建议是安排一个任务,当客人进入时,将在5000毫秒间隔后挑选客人。如果前一个guest虚拟机中的任务正在运行,请先取消它。

enter方法应该获取访客的锁(使用同步块)并让访客等待。选择应该在您选择的访客上调用notify()方法。这将允许他们继续执行。

从队列中删除选定的guest虚拟机时,请注意默认情况下Java集合不是线程安全的。您必须使用外部锁定以确保在添加和删除guest虚拟机时没有其他人正在修改您的列表。 Collections.synchronizedList(List)方法提供了一种方便的方法。

以下是讨论我提到的主题的链接列表:

  1. http://docs.oracle.com/javase/tutorial/essential/concurrency/(适合初学者的优秀教程)
  2. http://docs.oracle.com/javase/7/docs/api/java/util/Timer.html
  3. http://docs.oracle.com/javase/7/docs/api/java/util/TimerTask.html
  4. http://docs.oracle.com/javase/7/docs/api/java/util/Collections.html#synchronizedList%28java.util.List%29

答案 1 :(得分:1)

我可能会这样做。我会尽量避免使用notify / notifyAll,因为虚假的唤醒会让代码混乱,并且会使代码混乱不堪。虽然这个名字有点奇怪,但{IMO}在这里是一个更好的选择。

CountDownLatch