当我收到通知时,我需要异步执行更新操作。下面的update()方法操作实例变量。
public class UpdateOperation implements Runnable
{
private Boolean isInProgress = false;
@Override
public void run() {
try
{
synchronized (isInProgress)
{
isInProgress = true;
}
update(); //perform update
synchronized (isInProgress)
{
isInProgress = false;
}
}
catch (UpdaterException e)
{
// deal with it
}
}
}
// In another class
private UpdateOperation mCurrentUpdateOperation = new UpdateOperation();
public void updateRequired()
{
synchronized (mCurrentUpdateOperation.isInProgress)
{
if (!mCurrentUpdateOperation.isInProgress)
{
new Thread(mCurrentUpdateOperation).start();
}
else
{
// reschedule or silently ignore
}
}
}此设置是否足以让两(2)个更新操作同时运行?我相信这是因为到达synchronized块的第一个线程将获取锁,启动操作,并释放锁。然后第二个(或更多)将获取锁,查看操作正在进行,重新调度并释放锁。
这个设置会失败吗?
发布于 2013-01-24 03:14:59
此设置是否足以让两(2)个更新操作同时运行?
否,因为您正在锁定的对象。您应该始终在非最终对象上同步,而不是在Boolean上同步。当isInProgress的值改变时(当它被设置为true或false时),多个线程将锁定不同的对象,并且可以同时进入互斥锁块。
如果可以将其设置为final,那么您可以锁定您的UpdateOperation实例。你可以做一些类似这样的事情:
private final Object lockObject = new Object();
...
synchronized (lockObject) {
...
}一旦锁定了对象,就可以检查inProgress的状态,它可能是一个布尔型原语。synchronize构造同步所有内存。有关详细信息,请参阅Java thread tutorial on synchronization。
锁定一个Boolean是非常糟糕的,因为在整个JVM中只有2个常量的对象引用(除非您使用new Boolean(...))。当你说:
isInProgress = true;你实际上是在说:
isInProgress = Boolean.TRUE;因此,所有类中的所有线程都将锁定相同的两个对象,并产生奇怪的结果。
有关更多信息,请参阅此处的答案:
发布于 2013-01-24 03:21:31
看看Executor,他们会提供一个线程池,你可以简单地添加你的runnable。此外,您可能想要使用AtomicInteger。
我认为这将为你提供你想要的一切,更容易使用。
发布于 2013-01-24 13:04:00
原始解决方案的另一个问题是,检查和设置isInProgress变量是在不同的同步语句中进行的,这就造成了时间差距。因此,可能会启动多个线程。
正确的解决方案是:
public class UpdateOperation implements Runnable {
private boolean inProgress = false;
public void start() {
synchronized (this) {
if (inProgress) {
return;
}
inProgress=true;
}
new Thread(this).start();
}
@Override
public void run() {
try {
update(); //perform update
} catch (UpdaterException e) {
// deal with it
} finally {
synchronized (this) {
inProgress = false;
}
}
}
}
// In another class
private UpdateOperation mCurrentUpdateOperation = new UpdateOperation();
public void updateRequired() {
mCurrentUpdateOperation.start();
}https://stackoverflow.com/questions/14487539
复制相似问题