RefCountBase.java revision 80aed3c513dc6a6670e25ef6e11bc71ab6a2d9fd
1/*
2 * Copyright (C) 2014 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.android.camera.async;
18
19import com.google.common.base.Preconditions;
20
21/**
22 * Wraps an object with reference counting. When the reference count goes to 0
23 * for the first time, the object is closed.
24 */
25public class RefCountBase<T extends SafeCloseable> implements SafeCloseable {
26    private final Object mLock;
27    private final T mObject;
28    private int mRefCount;
29    private boolean mObjectClosed;
30
31    public RefCountBase(T object) {
32        this(object, 1);
33    }
34
35    public RefCountBase(T object, int initialReferenceCount) {
36        Preconditions.checkState(
37                initialReferenceCount > 0, "initialReferenceCount is not greater than 0.");
38        mLock = new Object();
39        mObject = object;
40        mRefCount = initialReferenceCount;
41        mObjectClosed = false;
42    }
43
44    public void addRef() {
45        synchronized (mLock) {
46            Preconditions.checkState(!mObjectClosed,
47                    "addRef on an object which has been closed.");
48            mRefCount++;
49        }
50    }
51
52    public T get() {
53        return mObject;
54    }
55
56    @Override
57    public void close() {
58        synchronized (mLock) {
59            // A SafeCloseable must tolerate multiple calls to close().
60            if (mObjectClosed) {
61                return;
62            }
63            mRefCount--;
64            if (mRefCount > 0) {
65                return;
66            }
67            mObjectClosed = true;
68        }
69        // Do this outside of the mLock critical section for speed and to avoid
70        // deadlock.
71        mObject.close();
72    }
73}
74