1

我有一个包含“资源管理器”类的多线程 Java 应用程序。

为此类提供了可以作为初始化参数请求的资源列表。然后,它检查每个文件的本地文件系统,并将确定为本地的文件添加到列表中。

当类收到资源请求时,会发生以下情况之一:

  1. 如果确定资源是本地的(在列表中):提供可以找到它的 URI。

  2. 如果资源是远程的(不在列表中):安排工作人员获取资源。任务完成后worker会通知manager,本地资源列表也会更新。(请求线程不要等待——它在那里或不在那里)。

由于多个线程可以请求资源,因此使用 ReadWriteLock 来协调列表访问。许多线程可以同时读取列表,当需要更新时,将使用 writeLock。

问题在于为任何特定的远程资源安排后台工作人员。如果多个线程为同一资源安排工作人员,则需要不必要的开销(即使重复任务由于检查这种情况而没有完全执行)。为了尽可能实现最高效率,我想知道以下实现:

private final ReadWriteLock lock = new ReentrantReadWriteLock();

//assume each resource object has a volatile boolean "scheduled"
//with isScheduled() and setSheduled() setter/getter;

//assume the resource list is thread safe

public URI requestResource(Resource theResource){
  URI resourceId = null;
  //many threads can enter here 
  lock.readLock().lock();
  try{
    //if our resource is not in the list
    if(!localResouces.contains(theResource)){
       //double-check idiom...does it work here?
       //if the resource isn't scheduled
       if(!theResource.isScheduled()){
          //only one thread may enter here
          synchronized(this){
            if(!theResource.isScheduled()){
               //schedule task here...
               theResource.setScheduled(true);                                      
            }
          }  
       }
    } else {
       //its local, return the location
       resouceId = theResource.getURI();
    }
  } finally {
    lock.readLock().unlock();
  }
//requesting object will deal with null value;
return resouceId;
}

当工人完成时:

public void update(Resource theResource){
  //ensures no threads in the read block
  lock.writeLock().lock();
  try {
      //update the list (would check result IRL, and not add if problem found)
      localResources.add(theResource);
      //set the scheduled field
      theResource.setScheduled(false); 
  } finally {
       lock.writeLock().unlock();
  }
}

同样,我想最大限度地提高效率。我找不到与这种情况相匹配的示例 - 即允许常见操作的高吞吐量,同时允许以最小的阻塞/开销安排任务。

这种方法有什么问题?第一种方法必须同时获得读锁和同步,但是更新方法只需要获得写锁,因为isScheduled的检查被封装在读块中。这是否提供线程安全调度和数据访问?

编辑:

我已经测试了上述方法,我看到了正确的行为。我仍然不确定这是否真的是“线程安全的”。

4

1 回答 1

1

我可能会这样做:

class Resource

    Uri localUri;
    volatile int state; // REMOTE, FETCHING, LOCAL

    Resource()
        if local
            localUri = ...;
            state = LOCAL;
        else
            state = REMOTE

    URI requestResource()

        if(state==LOCAL)  // volatile read
            return localUri;
        if(state==FETCHING)
            return null;

        synchronized(lock)
            if(state==LOCAL)
                return localUri;
            if(state==FETCHING)
                return null;

            // REMOTE, and it's my job to initiate fetching
            state=FETCHING;
            // do actaul fetching outside synchronized block

        schedule fetching...

    void onFetchingDone()

        synchronized(lock)

            if error
                state=REMOTE; // to retry.
                // if we consider error unrecoverable,
                // we need an ERROR state.
            else
                ...
                loalUri = ...;
                state = LOCAL;  // volatile write
于 2013-02-18T22:54:30.973 回答