1 /*
2 * Copyright 2021 The Netty Project
3 *
4 * The Netty Project licenses this file to you under the Apache License,
5 * version 2.0 (the "License"); you may not use this file except in compliance
6 * with the License. You may obtain a copy of the License at:
7 *
8 * https://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, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations
14 * under the License.
15 */
16 package io.netty5.buffer.api.internal;
17
18 import io.netty5.buffer.api.MemoryManager;
19
20 import java.util.List;
21 import java.util.ServiceLoader;
22 import java.util.ServiceLoader.Provider;
23 import java.util.concurrent.atomic.AtomicReference;
24 import java.util.concurrent.locks.ReentrantLock;
25 import java.util.stream.Collectors;
26 import java.util.stream.Stream;
27
28 public final class MemoryManagerLoader {
29 /**
30 * Cache the service loader result to reduce cost of repeated calls.
31 * However, also place the cached loader field in a dedicated class, so the service loading is performed lazily,
32 * on class initialisation, when (and if) needed.
33 * {@link ServiceLoader} objects are not actually thread-safe, so instead of caching the loader itself, we
34 * cache its result.
35 * This becomes a bit more complicated by the fact that the service-loader stream is lazy.
36 */
37 private static final AtomicReference<List<Provider<MemoryManager>>> CACHE = new AtomicReference<>();
38 private static final ReentrantLock CACHE_POP_LOCK = new ReentrantLock();
39
40 private MemoryManagerLoader() {
41 }
42
43 /**
44 * @see MemoryManager#availableManagers()
45 */
46 public static Stream<Provider<MemoryManager>> stream() {
47 var cachedList = CACHE.get();
48 if (cachedList != null) {
49 return cachedList.stream();
50 }
51 CACHE_POP_LOCK.lock();
52 try {
53 cachedList = CACHE.get();
54 if (cachedList != null) {
55 return cachedList.stream();
56 }
57 var loader = ServiceLoader.load(MemoryManager.class);
58 cachedList = List.copyOf(loader.stream().collect(Collectors.toList()));
59 CACHE.set(cachedList);
60 return cachedList.stream();
61 } finally {
62 CACHE_POP_LOCK.unlock();
63 }
64 }
65 }