/
LazyInit.java
67 lines (64 loc) · 2.87 KB
/
LazyInit.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
/*
* Copyright 2015 The Error Prone Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.google.errorprone.annotations.concurrent;
import com.google.errorprone.annotations.IncompatibleModifiers;
import com.google.errorprone.annotations.Modifier;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Use this annotation on any static or field that will be initialized lazily, where races yield no
* semantic difference in the code (as, for example, is the case with {@link String#hashCode}). Note
* that lazily initializing a non-volatile field is hard to do correctly, and one should rarely use
* this. It should also only be done by developers who clearly understand the potential issues, and
* then, always using the pattern as presented in the {@code getData} method of this sample code
* below:
*
* <pre>{@code
* private final String source;
* {@literal @}LazyInit private String data;
*
* public String getData() {
* String local = data;
* if (local == null) {
* data = local = expensiveCalculation(source);
* }
* return local;
* }
*
* private static String expensiveCalculation(String string) {
* return string.replaceAll(" ", "_");
* }
* }</pre>
*
* <p>The need for using the {@code local} variable is detailed in
* http://jeremymanson.blogspot.com/2008/12/benign-data-races-in-java.html (see, particularly, the
* part after "Now, let's break the code").
*
* <p>Also note that {@code LazyInit} must not be used on 64-bit primitives ({@code long}s and
* {@code double}s), because the Java Language Specification does not guarantee that writing to
* these is atomic. Furthermore, when used for non-primitives, the non-primitive must be either
* truly immutable or at least thread safe (in the Java memory model sense). And callers must
* accommodate the fact that different calls to something like the above getData() method may return
* different (though identically computed) objects, with different identityHashCode() values. Again,
* unless you really understand this <b>and</b> you really need the performance benefits of
* introducing the data race, do not use this construct.
*/
@IncompatibleModifiers(modifier = {Modifier.FINAL})
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface LazyInit {}