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