同步与条件一起工作?如何使这个代码具有高性能和线程安全性?

时间:2012-02-12 00:31:33

标签: java synchronization thread-safety

给出以下代码:

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 个答案:

答案 0 :(得分:4)

double checked non-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);
    }
}

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

答案 1 :(得分: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);
    }
  }
}