我正在开发一个多线程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();
}
我希望 foo 和 foobar 立即打印(顺序无关紧要),然后在 bar 之后一秒钟。如果cooldown()
只调用了Thread.currentThread().sleep(ms)
而不是当前的实现,那么 foo 会立即打印,然后是 foobar 和 bar 一秒钟之后。
答案 0 :(得分:0)
您有以下选项:
如果在synchronized方法中调用,Thread.sleep()应该可以正常工作。将阻止所有其他线程,并且您的线程将保持锁定并等待。
在同步块中使用定时等待/通知。那也应该做好。
编辑:
请参阅以下代码
公共类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);
}
}
答案 1 :(得分:0)
我喜欢使用类似Thread.sleep()的构造,但在这种情况下,这会产生强制调用线程进入休眠状态并且不会阻止任何其他线程在A上进行方法调用的不良影响。建议?
除了旋转循环浪费CPU之外,我没有看到调用Thread.sleep()
与旋转循环之间的区别。如果您在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);
}
答案 2 :(得分:0)
你已经非常接近了......微小的改变......
private synchronized void cooldown(long ms) throws InterruptedException {
Thead.sleep(ms);
}
或者,您可以在冷却方法中处理InterruptedException
。
另请注意,您的代码实际上可以按任何顺序执行foo
,bar
和foobar
。冷却时间会减慢foo
或bar
(取决于先执行哪个)。
我喜欢使用类似Thread.sleep()的构造,但在这种情况下, 这会产生强制调用线程的不良影响 睡眠并且不阻止任何其他线程进行方法调用 在A。
你的方法做你想要的。其他线程被阻止在A上进行方法调用(如果你已经同步了方法 - 你有)。