簡體   English   中英

兩個線程之間的資源同步訪問

[英]synchronized access of resource between two threads

我有兩個線程和一個緩存。 我們將線程1稱為Tb,它是一個后台線程(即優先級較低),另一個線程稱為Tm(主線程具有較高優先級)。 這兩個線程都更新了一個緩存。 您可以說線程Tb是Tm的助手,它可以在可能時搶先填充緩存。

問題是,當Tm要訪問緩存時,它必須立即訪問它,因為某些UI更新顯示取決於它。

由於共享了緩存以進行並發寫入,因此我可以按以下方式同步訪問緩存:

Element checkAndUpdateCache(int elementPositionToBeChecked){

  Element toBeReturned;

  synchronized(lock){

    // Check if the element is already present in the cache
    if(!cache.hasElement(elementPositionToBeChecked)){

      // If not, retrieve a new one and fill the cache
      toBeReturned = retrieveNewElement(elementPositionToBeChecked);
      cache.put(elementPositionToBeChecked, toBeReturned );
    }
    else{
      toBeReturned = cache.getElement(elementPositionToBeChecked);
    }

  }

  return toBeReturned;

}

問題在於,由於后台線程正在循環中調用此方法,因此需要非常快速地連續訪問緩存,並且幾乎永遠不會釋放鎖。 當前,我在每個循環周期后調用Thread.yield(),並另外調用Thread.sleep(10)以便對主線程進行一些訪問。

具有不同的優先級實際上並沒有幫助,在每個循環周期中調用Thread.yield()也不起作用。 Thread.sleep()確實有所幫助,但我認為,我們都同意,這根本不是一個好的策略。 畢竟,我們想要最大的CPU使用率,對嗎?

是否有某種方法可以確保主線程每當需要訪問高速緩存時,便隨時獲得高速緩存,而后台線程等待它,然后稍后再恢復操作?

編輯:實施細節

緩存是Map<Integer, Album> ,其中鍵是Integer

public static Album getAlbum(Context context, int position, @NonNull Cursor cursor, @NonNull Map<Integer, Album> cache){

        // Do we have the Album in cache
        Album albumInfo = cache.get(position);

        if(albumInfo == null){

            cursor.moveToPosition(position);

            // Let's cache this Album
            albumInfo = Album.fromMediaStoreCursor(context, cursor);
            cache.put(position, albumInfo);
        }
EDIT 2
        return albumInfo;
    }

編輯2 :正在節流的后台線程循環

// While we pre-emptively fetch the Albums to cache in the background :)
if (cursorImages != null) {

    for (int i = 0; i < cursorImages.getCount(); i++) {

        synchronized(SnapsboardApplication.getInstance()) {
            AlbumsListCursorAdapter.getAlbum(ListPhotoVideoAlbumsOnDeviceActivity.this,
                i, cursorImages, cache);
        }

        // Keep checking if we have been asked to cancel
        if (isCancelled()) {
            return null;
        }

        try {
            Thread.sleep(10);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
        Thread.yield();
    }
}

在不知道完整的實現的情況下,很難給出真正好的建議,但是我想到的一種可能的解決方案是將地圖的定義更改為Map<Integer, Future<Album>>並使用ExecuterService檢索要添加到的數據。地圖。 這樣一來,后台線程在方法retrieveNewElement(elementPositionToBeChecked)不應停留太長時間(我假設這是您的主線程被阻塞的原因),即使檢索未完成,您的主線程也已經獲得了結果,然而。 調用future.get(timeout, TimeUnit.SECONDS)將返回所需的值或將阻塞直到檢索完成(或達到超時)。

線程Tb是用於在后台准備數據的助手。 如果必須保留線程Tb,則需要一種機制來通知線程Tb停止/恢復工作(進一步,通知線程Tb准備哪些數據)。

丑陋地,聲明一個volatile boolean work

線程Tm。 輸入checkAndUpdateCache

...
work = false;
synchronized(lock) {
    ...
    work = true;
    lock.notify();
}

線程Tb。 輸入checkAndUpdateCache

...
synchronized(lock) {
    while (!work) {
        lock.wait();
    }
    ...
}

但是,我認為這個問題不是唯一的問題。 例如:

  • Tb如何決定是繼續准備數據還是准備准備哪些數據。
  • 線程Tb / Tm需要不同的功能入口來做不同的事情。
  • 是否有必要在鎖中調用retrieveNewElement 也許release lock, retrieveNewElement, relock and put會更好。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM