2012-02-12 28 views
1

考虑下面的代码:同步使用条件?我怎样才能使这个代码的性能和线程安全?

public class SomeClass { 

    private boolean shouldBlock = false; 
    private Object resource; 

    public void handleDrawRequest(Canvas canvas) { 
    if (!shouldBlock && resource == null) 
    { 
     shouldBlock = true; 
     loadTheResource(); //which takes awhile 
     shouldBlock = false; 
    } 
    else if (shouldBlock && resrouce == null) 
    { 
     return; //another thread is taking care of the loading of the resource 
       //and its not ready yet, so just ignore this request 
    } 

    drawResourceOn(canvas); 
    } 
} 

我怎样才能使此代码线程安全的?我试图完成的是只有一个线程来加载资源,同时任何其他线程试图同时访问此代码将被丢弃(例如,遵循'else if'逻辑)直到资源被加载。可能有很多线程试图同时访问这些代码,我不想同步整个方法并且有一堆线程堆积起来。

回答

2

你正在寻找一个AtomicBoolean

public class SomeClass { 
    // AtomicBolean defaults to the value false. 
    private AtomicBoolean loadingResource = new AtomicBoolean(); 
    private volatile Object resource; 

    public void handleDrawRequest(Canvas canvas) { 
    if (resource == null) { 
     if (loadingResource.compareAndSet(false, true)) { 
     loadTheResource(); //which takes awhile 
     } else { 
     //another thread is taking care of the loading of the resource 
     //and its not ready yet, so just ignore this request 
     return; 
     } 
    } else { 
     drawResourceOn(canvas); 
    } 
    } 
} 
+0

不确定你是否需要资源'volatile'。 – OldCurmudgeon 2012-02-12 01:51:02

+0

看起来不错,简单。但是,加载资源可能会失败,将资源留空,我希望将来的线程能够重新加载资源。 AtomicReference 可以帮助吗?或者就像在loadTheResource()之后添加loadingResource.compareAndSet(true,false)一样简单? – 2012-02-12 08:31:35

+0

@Chris,如果加载资源失败,AtomicBoolean可以重置为false。 – Scorpion 2012-02-12 10:32:39

4

随着double checkednon-blocking锁定:

public class SomeClass { 

    private Lock lock = new Lock(); 
    private volatile Object resource; 

    public void handleDrawRequest(Canvas canvas) { 
     if(resource==null) { 
      if(lock.tryLock()) { 
       try { 
        if(resource==null) 
         resource = loadResource(); 
       } 
       finally { 
        lock.unlock(); 
       } 
      } 
      else { 
       return; 
      } 
     } 
     drawResourceOn(canvas); 
    } 
} 

如果你不resourcevolatile,线程可以自由地高速缓存,并可能永远不会读取更新后的值。特别是,即使资源在第一个之后加载,第二个空检查也将始终返回true。

+0

尼斯一个,我创建了一个Eclipse的解决方案,然后发现这个问题的答案张贴:-) – 2012-02-12 03:06:29

+0

@Banthar看起来非常好感谢。你能解释一下使资源变得不稳定的必要吗? – 2012-02-12 08:21:26

+1

@ChrisKnight这是为了确保一个调用'resource = loadResource()'的线程与另一个线程看到一个非空'资源'之间发生的关系。如果没有'volatile',第二个线程可能会看到一个非null但部分构建的'resource'对象。 – yshavit 2012-02-12 10:16:08

相关问题