View Javadoc
1   /*
2    * Copyright 2013 The Netty Project
3    *
4    * The Netty Project licenses this file to you under the Apache License,
5    * version 2.0 (the "License"); you may not use this file except in compliance
6    * with the License. You may obtain a copy of the License at:
7    *
8    *   https://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, WITHOUT
12   * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13   * License for the specific language governing permissions and limitations
14   * under the License.
15   */
16  package io.netty.util;
17  
18  import java.lang.invoke.MethodHandles;
19  import java.lang.invoke.VarHandle;
20  import java.util.concurrent.atomic.AtomicIntegerFieldUpdater;
21  
22  import io.netty.util.internal.AtomicReferenceCountUpdater;
23  import io.netty.util.internal.PlatformDependent;
24  import io.netty.util.internal.ReferenceCountUpdater;
25  import io.netty.util.internal.ReferenceCountUpdater.UpdaterType;
26  import io.netty.util.internal.UnsafeReferenceCountUpdater;
27  import io.netty.util.internal.VarHandleReferenceCountUpdater;
28  
29  import static io.netty.util.internal.ReferenceCountUpdater.getUnsafeOffset;
30  import static java.util.concurrent.atomic.AtomicIntegerFieldUpdater.newUpdater;
31  
32  /**
33   * Abstract base class for classes wants to implement {@link ReferenceCounted}.
34   */
35  public abstract class AbstractReferenceCounted implements ReferenceCounted {
36      private static final long REFCNT_FIELD_OFFSET;
37      private static final AtomicIntegerFieldUpdater<AbstractReferenceCounted> AIF_UPDATER;
38      private static final Object REFCNT_FIELD_VH;
39      private static final ReferenceCountUpdater<AbstractReferenceCounted> updater;
40  
41      static {
42          UpdaterType updaterType = ReferenceCountUpdater.updaterTypeOf(AbstractReferenceCounted.class, "refCnt");
43          switch (updaterType) {
44              case Atomic:
45                  AIF_UPDATER = newUpdater(AbstractReferenceCounted.class, "refCnt");
46                  REFCNT_FIELD_OFFSET = -1;
47                  REFCNT_FIELD_VH = null;
48                  updater = new AtomicReferenceCountUpdater<AbstractReferenceCounted>() {
49                      @Override
50                      protected AtomicIntegerFieldUpdater<AbstractReferenceCounted> updater() {
51                          return AIF_UPDATER;
52                      }
53                  };
54                  break;
55              case Unsafe:
56                  AIF_UPDATER = null;
57                  REFCNT_FIELD_OFFSET = getUnsafeOffset(AbstractReferenceCounted.class, "refCnt");
58                  REFCNT_FIELD_VH = null;
59                  updater = new UnsafeReferenceCountUpdater<AbstractReferenceCounted>() {
60                      @Override
61                      protected long refCntFieldOffset() {
62                          return REFCNT_FIELD_OFFSET;
63                      }
64                  };
65                  break;
66              case VarHandle:
67                  AIF_UPDATER = null;
68                  REFCNT_FIELD_OFFSET = -1;
69                  REFCNT_FIELD_VH = PlatformDependent.findVarHandleOfIntField(MethodHandles.lookup(),
70                          AbstractReferenceCounted.class, "refCnt");
71                  updater = new VarHandleReferenceCountUpdater<AbstractReferenceCounted>() {
72                      @Override
73                      protected VarHandle varHandle() {
74                          return (VarHandle) REFCNT_FIELD_VH;
75                      }
76                  };
77                  break;
78              default:
79                  throw new Error("Unexpected updater type for AbstractReferenceCounted: " + updaterType);
80          }
81      }
82  
83      // Value might not equal "real" reference count, all access should be via the updater
84      @SuppressWarnings({"unused", "FieldMayBeFinal"})
85      private volatile int refCnt = updater.initialValue();
86  
87      @Override
88      public int refCnt() {
89          return updater.refCnt(this);
90      }
91  
92      /**
93       * An unsafe operation intended for use by a subclass that sets the reference count of the buffer directly
94       */
95      protected final void setRefCnt(int refCnt) {
96          updater.setRefCnt(this, refCnt);
97      }
98  
99      @Override
100     public ReferenceCounted retain() {
101         return updater.retain(this);
102     }
103 
104     @Override
105     public ReferenceCounted retain(int increment) {
106         return updater.retain(this, increment);
107     }
108 
109     @Override
110     public ReferenceCounted touch() {
111         return touch(null);
112     }
113 
114     @Override
115     public boolean release() {
116         return handleRelease(updater.release(this));
117     }
118 
119     @Override
120     public boolean release(int decrement) {
121         return handleRelease(updater.release(this, decrement));
122     }
123 
124     private boolean handleRelease(boolean result) {
125         if (result) {
126             deallocate();
127         }
128         return result;
129     }
130 
131     /**
132      * Called once {@link #refCnt()} is equals 0.
133      */
134     protected abstract void deallocate();
135 }