1

当我收到通知时,我需要异步执行更新操作。下面的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块的线程将获取锁,启动操作,然后释放锁。然后第二个(或更多)将获取锁,查看操作正在进行中,重新调度并释放锁。

这个设置会失败吗?

4

3 回答 3

3

此设置是否足以同时运行两 (2) 个更新操作?

不,因为您锁定的对象。您应该始终在非最终对象上同步,而不是Boolean. 随着值的isInProgress变化(设置为truefalse),多个线程将锁定不同的对象,并可以同时进入互斥块。

如果可以,您可以锁定您的UpdateOperation实例final。您总是可以执行以下操作:

 private final Object lockObject = new Object();
 ...
 synchronized (lockObject) {
     ...
 }

锁定对象后,您可以检查inProgress可能是布尔原语的状态。该synchronize构造同步所有内存。有关更多信息,请参阅有关同步的 Java 线程教程

锁定 aBoolean特别糟糕,因为在整个 JVM 中它们只有 2 个常量对象引用(除非你这样做new Boolean(...))。当你说:

isInProgress = true;

你实际上是在说:

isInProgress = Boolean.TRUE;

所以所有中的所有线程都将锁定在相同的 2 个对象上,结果很奇怪。

有关更多信息,请参阅我的回答:

为什么在布尔值上同步不是一个好习惯?

于 2013-01-23T19:14:59.107 回答
1

原解决方案的另一个问题是检查和设置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();
}
于 2013-01-24T05:04:00.060 回答
1

看看Executor。他们将提供一个线程池,您可以简单地添加您可运行的。您也可能想使用 AtomicInteger。

我认为这将为您提供所需的一切,并且更易于使用。

于 2013-01-23T19:21:30.667 回答