11992d6153d12fcba5deca13f01509a823434100
[idea/community.git] / platform / util / src / com / intellij / util / concurrency / AtomicFieldUpdater.java
1 /*
2  * Copyright 2000-2016 JetBrains s.r.o.
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
17 package com.intellij.util.concurrency;
18
19 import com.intellij.util.ReflectionUtil;
20 import org.jetbrains.annotations.NotNull;
21 import sun.misc.Unsafe;
22
23 import java.lang.reflect.Field;
24 import java.lang.reflect.Modifier;
25
26 /**
27  * Utility class similar to {@link java.util.concurrent.atomic.AtomicReferenceFieldUpdater} except:
28  * - removed access check in getAndSet() hot path for performance
29  * - new methods "forFieldXXX" added that search by field type instead of field name, which is useful in scrambled classes
30  */
31 public class AtomicFieldUpdater<ContainingClass, FieldType> {
32   private static final Unsafe unsafe;
33   static {
34     unsafe = ReflectionUtil.getStaticFieldValue(Unsafe.class, Unsafe.class, "theUnsafe");
35     if (unsafe == null) {
36       throw new RuntimeException("Could not find 'theUnsafe' field in the " + Unsafe.class);
37     }
38   }
39
40   @NotNull
41   public static Unsafe getUnsafe() {
42     return unsafe;
43   }
44
45   private final long offset;
46
47   @NotNull
48   public static <T, V> AtomicFieldUpdater<T, V> forFieldOfType(@NotNull Class<T> ownerClass, @NotNull Class<V> fieldType) {
49     return new AtomicFieldUpdater<>(ownerClass, fieldType);
50   }
51
52   @NotNull
53   public static <T> AtomicFieldUpdater<T, Long> forLongFieldIn(@NotNull Class<T> ownerClass) {
54     return new AtomicFieldUpdater<>(ownerClass, long.class);
55   }
56
57   @NotNull
58   public static <T> AtomicFieldUpdater<T, Integer> forIntFieldIn(@NotNull Class<T> ownerClass) {
59     return new AtomicFieldUpdater<>(ownerClass, int.class);
60   }
61
62   @NotNull
63   public static <O,E> AtomicFieldUpdater<O, E> forField(@NotNull Field field) {
64     return new AtomicFieldUpdater<>(field);
65   }
66
67   private AtomicFieldUpdater(@NotNull Class<ContainingClass> ownerClass, @NotNull Class<FieldType> fieldType) {
68     this(ReflectionUtil.getTheOnlyVolatileInstanceFieldOfClass(ownerClass, fieldType));
69   }
70
71   private AtomicFieldUpdater(@NotNull Field field) {
72     field.setAccessible(true);
73     if (!Modifier.isVolatile(field.getModifiers()) || Modifier.isStatic(field.getModifiers())) throw new IllegalArgumentException(field + " must be volatile instance");
74     offset = unsafe.objectFieldOffset(field);
75   }
76
77   public boolean compareAndSet(@NotNull ContainingClass owner, FieldType expected, FieldType newValue) {
78     return unsafe.compareAndSwapObject(owner, offset, expected, newValue);
79   }
80
81   public boolean compareAndSetLong(@NotNull ContainingClass owner, long expected, long newValue) {
82     return unsafe.compareAndSwapLong(owner, offset, expected, newValue);
83   }
84
85   public boolean compareAndSetInt(@NotNull ContainingClass owner, int expected, int newValue) {
86     return unsafe.compareAndSwapInt(owner, offset, expected, newValue);
87   }
88
89   public void set(@NotNull ContainingClass owner, FieldType newValue) {
90     unsafe.putObjectVolatile(owner, offset, newValue);
91   }
92
93   public FieldType get(@NotNull ContainingClass owner) {
94     //noinspection unchecked
95     return (FieldType)unsafe.getObjectVolatile(owner, offset);
96   }
97 }