class RetrySynchronizationManager {

	private RetrySynchronizationManager() {
	}

	private static final ThreadLocal<RetryContext> context = new ThreadLocal<>();

	private static final Map<Thread, RetryContext> contexts = new ConcurrentHashMap<>();

	private static boolean useThreadLocal = true;

	/**
	 * Set to false to store the context in a map (keyed by the current thread) instead of
	 * in a {@link ThreadLocal}. Recommended when using virtual threads.
	 * @param use true to use a {@link ThreadLocal} (default true).
	 * @since 2.0.3
	 */
	public static void setUseThreadLocal(boolean use) {
		useThreadLocal = use;
	}

	/**
	 * Return true if contexts are held in a ThreadLocal (default) rather than a Map.
	 * @return the useThreadLocal
	 * @since 2.0.3
	 */
	public static boolean isUseThreadLocal() {
		return useThreadLocal;
	}

	/**
	 * Public accessor for the locally enclosing {@link RetryContext}.
	 * @return the current retry context, or null if there isn't one
	 */
	@Nullable
	public static RetryContext getContext() {
		if (useThreadLocal) {
			return context.get();
		}
		else {
			return contexts.get(Thread.currentThread());
		}
	}

	/**
	 * Method for registering a context - should only be used by {@link RetryOperations}
	 * implementations to ensure that {@link #getContext()} always returns the correct
	 * value.
	 * @param context the new context to register
	 * @return the old context if there was one
	 */
	@Nullable
	public static RetryContext register(RetryContext context) {
		if (useThreadLocal) {
			RetryContext oldContext = getContext();
			RetrySynchronizationManager.context.set(context);
			return oldContext;
		}
		else {
			RetryContext oldContext = contexts.get(Thread.currentThread());
			contexts.put(Thread.currentThread(), context);
			return oldContext;
		}
	}

	/**
	 * Clear the current context at the end of a batch - should only be used by
	 * {@link RetryOperations} implementations.
	 * @return the old value if there was one.
	 */
	@Nullable
	public static RetryContext clear() {<FILL_FUNCTION_BODY>}

}

		RetryContext value = getContext();
		RetryContext parent = value == null ? null : value.getParent();
		if (useThreadLocal) {
			RetrySynchronizationManager.context.set(parent);
		}
		else {
			if (parent != null) {
				contexts.put(Thread.currentThread(), parent);
			}
			else {
				contexts.remove(Thread.currentThread());
			}
		}
		return value;
	
<no_super_class>