19
19
20
20
import java .io .IOException ;
21
21
import java .util .Objects ;
22
+ import java .util .concurrent .atomic .AtomicBoolean ;
23
+ import java .util .concurrent .atomic .AtomicReference ;
22
24
import javax .annotation .Nullable ;
23
- import javax .annotation .concurrent .GuardedBy ;
24
25
import okhttp3 .MediaType ;
25
26
import okhttp3 .Request ;
26
27
import okhttp3 .ResponseBody ;
@@ -37,16 +38,11 @@ final class OkHttpCall<T> implements Call<T> {
37
38
private final okhttp3 .Call .Factory callFactory ;
38
39
private final Converter <ResponseBody , T > responseConverter ;
39
40
40
- private volatile boolean canceled ;
41
-
42
- @ GuardedBy ("this" )
43
- private @ Nullable okhttp3 .Call rawCall ;
44
-
45
- @ GuardedBy ("this" ) // Either a RuntimeException, non-fatal Error, or IOException.
46
- private @ Nullable Throwable creationFailure ;
47
-
48
- @ GuardedBy ("this" )
49
- private boolean executed ;
41
+ private final AtomicBoolean canceled = new AtomicBoolean (false );
42
+ private final AtomicBoolean executed = new AtomicBoolean (false );
43
+ private final AtomicReference <okhttp3 .Call > rawCallRef = new AtomicReference <>();
44
+ // Either a RuntimeException, non-fatal Error, or IOException.
45
+ private final AtomicReference <Throwable > creationFailureRef = new AtomicReference <>();
50
46
51
47
OkHttpCall (
52
48
RequestFactory requestFactory ,
@@ -68,7 +64,7 @@ public OkHttpCall<T> clone() {
68
64
}
69
65
70
66
@ Override
71
- public synchronized Request request () {
67
+ public Request request () {
72
68
try {
73
69
return getRawCall ().request ();
74
70
} catch (IOException e ) {
@@ -77,7 +73,7 @@ public synchronized Request request() {
77
73
}
78
74
79
75
@ Override
80
- public synchronized Timeout timeout () {
76
+ public Timeout timeout () {
81
77
try {
82
78
return getRawCall ().timeout ();
83
79
} catch (IOException e ) {
@@ -89,12 +85,12 @@ public synchronized Timeout timeout() {
89
85
* Returns the raw call, initializing it if necessary. Throws if initializing the raw call throws,
90
86
* or has thrown in previous attempts to create it.
91
87
*/
92
- @ GuardedBy ("this" )
93
88
private okhttp3 .Call getRawCall () throws IOException {
94
- okhttp3 .Call call = rawCall ;
89
+ okhttp3 .Call call = rawCallRef . get () ;
95
90
if (call != null ) return call ;
96
91
97
92
// Re-throw previous failures if this isn't the first attempt.
93
+ Throwable creationFailure = creationFailureRef .get ();
98
94
if (creationFailure != null ) {
99
95
if (creationFailure instanceof IOException ) {
100
96
throw (IOException ) creationFailure ;
@@ -107,10 +103,12 @@ private okhttp3.Call getRawCall() throws IOException {
107
103
108
104
// Create and remember either the success or the failure.
109
105
try {
110
- return rawCall = createRawCall ();
106
+ final okhttp3 .Call newCall = createRawCall ();
107
+ rawCallRef .compareAndSet (null , newCall );
108
+ return rawCallRef .get ();
111
109
} catch (RuntimeException | Error | IOException e ) {
112
110
throwIfFatal (e ); // Do not assign a fatal error to creationFailure.
113
- creationFailure = e ;
111
+ creationFailureRef . set ( e ) ;
114
112
throw e ;
115
113
}
116
114
}
@@ -119,22 +117,19 @@ private okhttp3.Call getRawCall() throws IOException {
119
117
public void enqueue (final Callback <T > callback ) {
120
118
Objects .requireNonNull (callback , "callback == null" );
121
119
122
- okhttp3 .Call call ;
123
- Throwable failure ;
124
-
125
- synchronized (this ) {
126
- if (executed ) throw new IllegalStateException ("Already executed." );
127
- executed = true ;
128
-
129
- call = rawCall ;
130
- failure = creationFailure ;
131
- if (call == null && failure == null ) {
132
- try {
133
- call = rawCall = createRawCall ();
134
- } catch (Throwable t ) {
135
- throwIfFatal (t );
136
- failure = creationFailure = t ;
137
- }
120
+ if (!executed .compareAndSet (false , true )) throw new IllegalStateException ("Already executed." );
121
+
122
+ okhttp3 .Call call = rawCallRef .get ();
123
+ Throwable failure = creationFailureRef .get ();
124
+
125
+ if (call == null && failure == null ) {
126
+ try {
127
+ call = createRawCall ();
128
+ rawCallRef .compareAndSet (null , call );
129
+ } catch (Throwable t ) {
130
+ throwIfFatal (t );
131
+ creationFailureRef .compareAndSet (null , t );
132
+ failure = t ;
138
133
}
139
134
}
140
135
@@ -143,7 +138,7 @@ public void enqueue(final Callback<T> callback) {
143
138
return ;
144
139
}
145
140
146
- if (canceled ) {
141
+ if (canceled . get () ) {
147
142
call .cancel ();
148
143
}
149
144
@@ -185,22 +180,19 @@ private void callFailure(Throwable e) {
185
180
}
186
181
187
182
@ Override
188
- public synchronized boolean isExecuted () {
189
- return executed ;
183
+ public boolean isExecuted () {
184
+ return executed . get () ;
190
185
}
191
186
192
187
@ Override
193
188
public Response <T > execute () throws IOException {
194
- okhttp3 .Call call ;
195
-
196
- synchronized (this ) {
197
- if (executed ) throw new IllegalStateException ("Already executed." );
198
- executed = true ;
199
-
200
- call = getRawCall ();
189
+ if (!executed .compareAndSet (false , true )) {
190
+ throw new IllegalStateException ("Already executed." );
201
191
}
202
192
203
- if (canceled ) {
193
+ okhttp3 .Call call = getRawCall ();
194
+
195
+ if (canceled .get ()) {
204
196
call .cancel ();
205
197
}
206
198
@@ -255,25 +247,21 @@ Response<T> parseResponse(okhttp3.Response rawResponse) throws IOException {
255
247
256
248
@ Override
257
249
public void cancel () {
258
- canceled = true ;
250
+ canceled . set ( true ) ;
259
251
260
- okhttp3 .Call call ;
261
- synchronized (this ) {
262
- call = rawCall ;
263
- }
252
+ okhttp3 .Call call = rawCallRef .get ();
264
253
if (call != null ) {
265
254
call .cancel ();
266
255
}
267
256
}
268
257
269
258
@ Override
270
259
public boolean isCanceled () {
271
- if (canceled ) {
260
+ if (canceled . get () ) {
272
261
return true ;
273
262
}
274
- synchronized (this ) {
275
- return rawCall != null && rawCall .isCanceled ();
276
- }
263
+ okhttp3 .Call call = rawCallRef .get ();
264
+ return call != null && call .isCanceled ();
277
265
}
278
266
279
267
static final class NoContentResponseBody extends ResponseBody {
0 commit comments