SerialBitmapReferenceCounter.java revision e356a4f7ddc93843f8a28d810ff4c8777032411c
1package com.bumptech.photos.resize.bitmap_recycle; 2 3import android.graphics.Bitmap; 4 5import java.util.Map; 6import java.util.concurrent.ConcurrentHashMap; 7import java.util.concurrent.ConcurrentLinkedQueue; 8 9/** 10 * Created with IntelliJ IDEA. 11 * User: sam 12 * Date: 6/4/13 13 * Time: 9:54 AM 14 * To change this template use File | Settings | File Templates. 15 */ 16public class ConcurrentBitmapReferenceCounter implements BitmapReferenceCounter { 17 18 private static class InnerTrackerPool { 19 private ConcurrentLinkedQueue<InnerTracker> pool = new ConcurrentLinkedQueue<InnerTracker>(); 20 21 public InnerTracker get() { 22 InnerTracker result = pool.poll(); 23 if (result == null) { 24 result = new InnerTracker(); 25 } 26 27 return result; 28 } 29 30 public void release(InnerTracker innerTracker) { 31 pool.offer(innerTracker); 32 } 33 } 34 35 private static class InnerTracker { 36 private volatile int refs = 0; 37 private volatile boolean pending = false; 38 39 public void acquire() { 40 pending = false; 41 synchronized (this) { 42 refs++; 43 } 44 } 45 46 public boolean release() { 47 synchronized (this) { 48 refs--; 49 } 50 51 return refs == 0 && !pending; 52 } 53 54 public boolean reject() { 55 pending = false; 56 return refs == 0; 57 } 58 59 public void markPending() { 60 pending = true; 61 } 62 } 63 64 private final Map<Integer, InnerTracker> counter; 65 private final BitmapPool target; 66 private final InnerTrackerPool pool = new InnerTrackerPool(); 67 68 public ConcurrentBitmapReferenceCounter(BitmapPool target, int bitmapsPerSize) { 69 this.target = target; 70 counter = new ConcurrentHashMap<Integer, InnerTracker>(bitmapsPerSize * 6, 0.75f, 4); 71 } 72 73 @Override 74 public void initBitmap(Bitmap toInit) { 75 counter.put(toInit.hashCode(), pool.get()); 76 } 77 78 @Override 79 public void acquireBitmap(Bitmap bitmap) { 80 get(bitmap).acquire(); 81 } 82 83 @Override 84 public void releaseBitmap(Bitmap bitmap) { 85 final InnerTracker tracker = get(bitmap); 86 if (tracker.release()) { 87 recycle(tracker, bitmap); 88 } 89 } 90 91 @Override 92 public void rejectBitmap(Bitmap bitmap) { 93 final InnerTracker tracker = get(bitmap); 94 if (tracker.reject()) { 95 recycle(tracker, bitmap); 96 } 97 } 98 99 @Override 100 public void markPending(Bitmap bitmap) { 101 get(bitmap).markPending(); 102 } 103 104 private InnerTracker get(Bitmap bitmap) { 105 return counter.get(bitmap.hashCode()); 106 } 107 108 private void recycle(InnerTracker tracker, Bitmap bitmap) { 109 counter.remove(bitmap.hashCode()); 110 pool.release(tracker); 111 target.put(bitmap); 112 } 113} 114