首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >仅当更新操作尚未运行时才在线程中运行该操作

仅当更新操作尚未运行时才在线程中运行该操作
EN

Stack Overflow用户
提问于 2013-01-24 03:13:30
回答 3查看 1K关注 0票数 1

当我收到通知时,我需要异步执行更新操作。下面的update()方法操作实例变量。

代码语言:javascript
复制
    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块的第一个线程将获取锁,启动操作,并释放锁。然后第二个(或更多)将获取锁,查看操作正在进行,重新调度并释放锁。

这个设置会失败吗?

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2013-01-24 03:14:59

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

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

如果可以将其设置为final,那么您可以锁定您的UpdateOperation实例。你可以做一些类似这样的事情:

代码语言:javascript
复制
 private final Object lockObject = new Object();
 ...
 synchronized (lockObject) {
     ...
 }

一旦锁定了对象,就可以检查inProgress的状态,它可能是一个布尔型原语。synchronize构造同步所有内存。有关详细信息,请参阅Java thread tutorial on synchronization

锁定一个Boolean是非常糟糕的,因为在整个JVM中只有2个常量的对象引用(除非您使用new Boolean(...))。当你说:

代码语言:javascript
复制
isInProgress = true;

你实际上是在说:

代码语言:javascript
复制
isInProgress = Boolean.TRUE;

因此,所有类中的所有线程都将锁定相同的两个对象,并产生奇怪的结果。

有关更多信息,请参阅此处的答案:

Why is it not a good practice to synchronize on Boolean?

票数 3
EN

Stack Overflow用户

发布于 2013-01-24 03:21:31

看看Executor,他们会提供一个线程池,你可以简单地添加你的runnable。此外,您可能想要使用AtomicInteger。

我认为这将为你提供你想要的一切,更容易使用。

票数 1
EN

Stack Overflow用户

发布于 2013-01-24 13:04:00

原始解决方案的另一个问题是,检查和设置isInProgress变量是在不同的同步语句中进行的,这就造成了时间差距。因此,可能会启动多个线程。

正确的解决方案是:

代码语言:javascript
复制
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();
}
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/14487539

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档