2

我正在开发一个多线程 Java 项目,在该项目中我希望有一些对象可以防止在一段时间内从任何线程调用它们的方法。理想情况下,这些方法调用不会被丢弃,而只是排队等待前一个方法的冷却完成。这是一个具有这种功能的类的简单示例:

public class A {

    private synchronized void cooldown(long ms) {
        long finishTime = ms + System.currentTimeMillis();
        while (System.currentTimeMillis() < finishTime);
    }

    public synchronized void foo() {
        // foo's code
        cooldown(1000);
    }

    public synchronized void bar() {
        // bar's code
        cooldown(2000);
    }

}

这行得通,但我希望有很多上述对象,我觉得里面的循环cooldown()很浪费。我很想使用类似的构造Thread.sleep(),但在这种情况下,这会产生强制调用线程睡眠并且不会阻止任何其他线程对 进行方法调用的不良影响A。有什么建议么?

编辑:

为了澄清,给定以下实现:

public synchronized void foo() {
    System.out.println("foo");
    cooldown(1000);
}

public synchronized void bar() {
    System.out.println("bar");
    cooldown(2000);
}

public static void main(String[] args) {
    final A a = new A();

    new Thread(new Runnable() {
        public void run() {
            a.foo();
        }
    }).start();

    System.out.println("foobar");

    new Thread(new Runnable() {
        public void run() {
            a.bar();
        }
    }).start();
}

我希望foofoobar立即打印(顺序无关紧要),然后是bar一秒钟后。如果cooldown()只是调用Thread.currentThread().sleep(ms)而不是当前的实现,那么foo将立即打印,然后是foobarbar一秒钟后。

4

3 回答 3

0

你已经非常接近了......微小的变化......

private synchronized void cooldown(long ms) throws InterruptedException {
    Thead.sleep(ms);
}

或者,您可以InterruptedException在冷却方法本身中处理。

另外,请注意,您的代码实际上可以按任何顺序执行foobarfoobarfoo冷却时间会减慢bar(取决于哪个先执行)。

我很想使用像 Thread.sleep() 这样的构造,但在这种情况下,这会产生强制调用线程睡眠并且不会阻止任何其他线程对 A 进行方法调用的不良影响。

你的方法做你想做的事。其他线程被阻止对 A 进行方法调用(如果您已同步方法 - 您拥有)。

于 2013-04-29T04:45:26.097 回答
0

您有以下选择:

  1. 如果在同步方法中调用 Thread.sleep() 应该可以正常工作。所有其他线程都将被阻止,您的线程将保持锁定并等待。

  2. 在同步块中使用定时等待/通知。这也应该做的工作。

编辑:

请参阅下面的代码

公共类 A {

final volatile Object lck = new Object();
volatile boolean waitStatus = true;

private void cooldown(long ms) {        

    synchronized(lck){
       long startTime = System.currentTimeMillis();

       //Do thread need to wait
       if(waitStatus){
         while(System.currentTimeMillis()-startTime < ms) 
          lck.wait(gapTime);

        //Wait over no other thread will wait           
        waitStatus = false;  
       }    


    }
}

public  void foo() {
    // foo's code
    cooldown(1000);
}

public void bar() {
    // bar's code
    cooldown(2000);
}

}

于 2013-04-29T03:59:09.017 回答
0

我很想使用像 Thread.sleep() 这样的构造,但在这种情况下,这会产生强制调用线程睡眠并且不会阻止任何其他线程对 A 进行方法调用的不良影响。有什么建议吗?

Thread.sleep()除了自旋循环浪费 CPU 的事实之外,我看不出调用与自旋循环之间的区别。如果你在里面cooldown(...),那么那个实例A就是synchronized

如果您的意思是您有其他方法synchronized并且您不希望正在冷却的线程持有锁,那么您可以使用this.wait(...)它将在睡眠期间释放锁。当然是有人打电话notify(...)这行不通。

private synchronized void cooldown(long ms) {
    try {
       long waitUntilMillis = System.currentTimeMillis() + ms;
       long waitTimeMillis = ms;
       do {
          this.wait(waitTimeMillis);
          // we need this dance/loop because of spurious wakeups, thanks @loki
          waitTimeMillis = waitUntilMillis - System.currentTimeMillis();
       } while (waitTimeMillis > 0);
    } catch (InterruptedException e) {
       Thread.currentThread.interrupt();
    }
}

正确的做法是没有synchronized方法,仅在您特别需要时进行同步。然后您可以轻松冷却而无需锁定。

private void cooldown(long ms) {
    try {
       this.sleep(ms);
    } catch (InterruptedException e) {
       Thread.currentThread.interrupt();
    }
}
public void foo() { 
    synchronized (this) {
       // foo's code
    }
    cooldown(1000);
}
于 2013-04-29T04:06:11.667 回答