22
22
import com .optimizely .ab .optimizelyconfig .OptimizelyConfig ;
23
23
import com .optimizely .ab .optimizelyconfig .OptimizelyConfigManager ;
24
24
import com .optimizely .ab .optimizelyconfig .OptimizelyConfigService ;
25
+ import java .util .concurrent .locks .ReentrantLock ;
26
+ import javax .annotation .Nullable ;
25
27
import org .slf4j .Logger ;
26
28
import org .slf4j .LoggerFactory ;
27
29
@@ -60,6 +62,7 @@ public abstract class PollingProjectConfigManager implements ProjectConfigManage
60
62
private volatile String sdkKey ;
61
63
private volatile boolean started ;
62
64
private ScheduledFuture <?> scheduledFuture ;
65
+ private ReentrantLock lock = new ReentrantLock ();
63
66
64
67
public PollingProjectConfigManager (long period , TimeUnit timeUnit ) {
65
68
this (period , timeUnit , Long .MAX_VALUE , TimeUnit .MILLISECONDS , new NotificationCenter ());
@@ -70,6 +73,15 @@ public PollingProjectConfigManager(long period, TimeUnit timeUnit, NotificationC
70
73
}
71
74
72
75
public PollingProjectConfigManager (long period , TimeUnit timeUnit , long blockingTimeoutPeriod , TimeUnit blockingTimeoutUnit , NotificationCenter notificationCenter ) {
76
+ this (period , timeUnit , blockingTimeoutPeriod , blockingTimeoutUnit , notificationCenter , null );
77
+ }
78
+
79
+ public PollingProjectConfigManager (long period ,
80
+ TimeUnit timeUnit ,
81
+ long blockingTimeoutPeriod ,
82
+ TimeUnit blockingTimeoutUnit ,
83
+ NotificationCenter notificationCenter ,
84
+ @ Nullable ThreadFactory customThreadFactory ) {
73
85
this .period = period ;
74
86
this .timeUnit = timeUnit ;
75
87
this .blockingTimeoutPeriod = blockingTimeoutPeriod ;
@@ -78,7 +90,7 @@ public PollingProjectConfigManager(long period, TimeUnit timeUnit, long blocking
78
90
if (TimeUnit .SECONDS .convert (period , this .timeUnit ) < 30 ) {
79
91
logger .warn ("Polling intervals below 30 seconds are not recommended." );
80
92
}
81
- final ThreadFactory threadFactory = Executors .defaultThreadFactory ();
93
+ final ThreadFactory threadFactory = customThreadFactory != null ? customThreadFactory : Executors .defaultThreadFactory ();
82
94
this .scheduledExecutorService = Executors .newSingleThreadScheduledExecutor (runnable -> {
83
95
Thread thread = threadFactory .newThread (runnable );
84
96
thread .setDaemon (true );
@@ -176,43 +188,58 @@ public String getSDKKey() {
176
188
return this .sdkKey ;
177
189
}
178
190
179
- public synchronized void start () {
180
- if (started ) {
181
- logger .warn ("Manager already started." );
182
- return ;
183
- }
191
+ public void start () {
192
+ lock .lock ();
193
+ try {
194
+ if (started ) {
195
+ logger .warn ("Manager already started." );
196
+ return ;
197
+ }
184
198
185
- if (scheduledExecutorService .isShutdown ()) {
186
- logger .warn ("Not starting. Already in shutdown." );
187
- return ;
188
- }
199
+ if (scheduledExecutorService .isShutdown ()) {
200
+ logger .warn ("Not starting. Already in shutdown." );
201
+ return ;
202
+ }
189
203
190
- Runnable runnable = new ProjectConfigFetcher ();
191
- scheduledFuture = scheduledExecutorService .scheduleAtFixedRate (runnable , 0 , period , timeUnit );
192
- started = true ;
204
+ Runnable runnable = new ProjectConfigFetcher ();
205
+ scheduledFuture = scheduledExecutorService .scheduleAtFixedRate (runnable , 0 , period , timeUnit );
206
+ started = true ;
207
+ } finally {
208
+ lock .unlock ();
209
+ }
193
210
}
194
211
195
- public synchronized void stop () {
196
- if (!started ) {
197
- logger .warn ("Not pausing. Manager has not been started." );
198
- return ;
199
- }
212
+ public void stop () {
213
+ lock .lock ();
214
+ try {
215
+ if (!started ) {
216
+ logger .warn ("Not pausing. Manager has not been started." );
217
+ return ;
218
+ }
200
219
201
- if (scheduledExecutorService .isShutdown ()) {
202
- logger .warn ("Not pausing. Already in shutdown." );
203
- return ;
204
- }
220
+ if (scheduledExecutorService .isShutdown ()) {
221
+ logger .warn ("Not pausing. Already in shutdown." );
222
+ return ;
223
+ }
205
224
206
- logger .info ("pausing project watcher" );
207
- scheduledFuture .cancel (true );
208
- started = false ;
225
+ logger .info ("pausing project watcher" );
226
+ scheduledFuture .cancel (true );
227
+ started = false ;
228
+ } finally {
229
+ lock .unlock ();
230
+ }
209
231
}
210
232
211
233
@ Override
212
- public synchronized void close () {
213
- stop ();
214
- scheduledExecutorService .shutdownNow ();
215
- started = false ;
234
+ public void close () {
235
+ lock .lock ();
236
+ try {
237
+ stop ();
238
+ scheduledExecutorService .shutdownNow ();
239
+ started = false ;
240
+ } finally {
241
+ lock .unlock ();
242
+ }
216
243
}
217
244
218
245
protected void setSdkKey (String sdkKey ) {
0 commit comments