8
8
9
9
package org .elasticsearch .core ;
10
10
11
+ import java .lang .invoke .MethodHandles ;
12
+ import java .lang .invoke .VarHandle ;
11
13
import java .util .Objects ;
12
- import java .util .concurrent .atomic .AtomicInteger ;
13
14
14
15
/**
15
16
* A basic {@link RefCounted} implementation that is initialized with a ref count of 1 and calls {@link #closeInternal()} once it reaches
16
17
* a 0 ref count.
17
18
*/
18
19
public abstract class AbstractRefCounted implements RefCounted {
20
+
19
21
public static final String ALREADY_CLOSED_MESSAGE = "already closed, can't increment ref count" ;
20
22
21
- private final AtomicInteger refCount = new AtomicInteger (1 );
23
+ private static final VarHandle VH_REFCOUNT_FIELD ;
24
+
25
+ static {
26
+ try {
27
+ VH_REFCOUNT_FIELD = MethodHandles .lookup ()
28
+ .in (AbstractRefCounted .class )
29
+ .findVarHandle (AbstractRefCounted .class , "refCount" , int .class );
30
+ } catch (NoSuchFieldException | IllegalAccessException e ) {
31
+ throw new RuntimeException (e );
32
+ }
33
+ }
34
+
35
+ @ SuppressWarnings ("FieldMayBeFinal" ) // updated via VH_REFCOUNT_FIELD (and _only_ via VH_REFCOUNT_FIELD)
36
+ private volatile int refCount = 1 ;
22
37
23
38
protected AbstractRefCounted () {}
24
39
@@ -32,9 +47,9 @@ public final void incRef() {
32
47
@ Override
33
48
public final boolean tryIncRef () {
34
49
do {
35
- int i = refCount . get () ;
50
+ int i = refCount ;
36
51
if (i > 0 ) {
37
- if (refCount . compareAndSet ( i , i + 1 )) {
52
+ if (VH_REFCOUNT_FIELD . weakCompareAndSet ( this , i , i + 1 )) {
38
53
touch ();
39
54
return true ;
40
55
}
@@ -47,9 +62,9 @@ public final boolean tryIncRef() {
47
62
@ Override
48
63
public final boolean decRef () {
49
64
touch ();
50
- int i = refCount . decrementAndGet ( );
51
- assert i >= 0 : "invalid decRef call: already closed" ;
52
- if (i == 0 ) {
65
+ int i = ( int ) VH_REFCOUNT_FIELD . getAndAdd ( this , - 1 );
66
+ assert i > 0 : "invalid decRef call: already closed" ;
67
+ if (i == 1 ) {
53
68
try {
54
69
closeInternal ();
55
70
} catch (Exception e ) {
@@ -63,7 +78,7 @@ public final boolean decRef() {
63
78
64
79
@ Override
65
80
public final boolean hasReferences () {
66
- return refCount . get () > 0 ;
81
+ return refCount > 0 ;
67
82
}
68
83
69
84
/**
@@ -73,7 +88,7 @@ public final boolean hasReferences() {
73
88
protected void touch () {}
74
89
75
90
protected void alreadyClosed () {
76
- final int currentRefCount = refCount . get () ;
91
+ final int currentRefCount = refCount ;
77
92
assert currentRefCount == 0 : currentRefCount ;
78
93
throw new IllegalStateException (ALREADY_CLOSED_MESSAGE );
79
94
}
@@ -82,7 +97,7 @@ protected void alreadyClosed() {
82
97
* Returns the current reference count.
83
98
*/
84
99
public final int refCount () {
85
- return this . refCount . get () ;
100
+ return refCount ;
86
101
}
87
102
88
103
/**
0 commit comments