Skip to content

Instantly share code, notes, and snippets.

@ok3141
Created April 20, 2023 13:24
Show Gist options
  • Save ok3141/eedfdcdb6297294ffa4269f712d7b3b5 to your computer and use it in GitHub Desktop.
Save ok3141/eedfdcdb6297294ffa4269f712d7b3b5 to your computer and use it in GitHub Desktop.
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Executor;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.function.BiFunction;
import java.util.function.Function;
public class Main {
private static final Random random = new Random();
public static void main(String[] args) throws InterruptedException {
ExecutorService executor = Executors.newSingleThreadExecutor();
CommandExecutor commandExecutor = new CommandExecutorImpl(executor, Main::handleUrlSync);
for (int i = 0; i < 100; ++i) {
String url = "url" + (random.nextInt(10) + 1);
commandExecutor.requestAsync(url, Main::print);
Thread.sleep(random.nextInt(200));
}
executor.shutdown();
}
private static String handleUrlSync(String url) {
long start = System.currentTimeMillis();
try {
Thread.sleep(random.nextInt(2000));
} catch (InterruptedException ex) {
throw new RuntimeException(ex);
}
long end = System.currentTimeMillis();
return start + " .. " + end;
}
private static Void print(String key, String value) {
System.out.println(key + " > " + value);
return null;
}
interface CommandExecutor {
void requestAsync(String url, BiFunction<String, String, Void> callback);
}
static class CommandExecutorImpl implements CommandExecutor {
private final Executor executor;
private final Function<String, String> urlHandler;
private final ConcurrentHashMap<String, List<BiFunction<String, String, Void>>> callbacks = new ConcurrentHashMap<>();
public CommandExecutorImpl(Executor executor, Function<String, String> urlHandler) {
this.executor = executor;
this.urlHandler = urlHandler;
}
@Override
public void requestAsync(String url, BiFunction<String, String, Void> callback) {
List<BiFunction<String, String, Void>> list = callbacks.computeIfAbsent(url, $ -> new ArrayList<>());
synchronized (list) {
list.add(callback);
if (list.size() == 1) {
executor.execute(() -> handleUrl(url, list));
}
}
}
@SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter")
private void handleUrl(String url, List<BiFunction<String, String, Void>> list) {
String response = urlHandler.apply(url);
if (callbacks.remove(url) != list) {
throw new IllegalStateException();
}
synchronized (list) {
for (BiFunction<String, String, Void> callback : list) {
callback.apply(url, response);
}
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment