Singletons and MainActor isolation

I'm building a caching layer for my SwiftUI app's network layer whereby:

(1) All requests to the same backend endpoint are merged into one request and the result is returned to all callers.

(2) The results of GET requests are cached in memory and on disk; the cached objects can be returned to the callers unless an object's TTL is expired or an explicit refresh is requested.

I've used this pattern in my apps for years using my library Multiplexer. It's entirely based on callbacks and implies everything happens on the main thread.

Now I'm trying to rewrite this library to use structured concurrency and actually benefit from multithreading. The async/await version of this library is indeed simpler and easier to read, however because the functionality implies shared states I'm still stuck in MainActor.

Here is the pattern I'm using for what I call "multiplexing" - combining multiple calls to the same endpoint into one (this is a greatly simplified version of the actual function that omits many details):

class Multiplexer<T> {
    let onFetch: @Sendable @escaping () async throws -> T

    private var task: Task<T, Error>?

    func request()  async throws -> T {
        if task == nil {
            task = Task(operation: onFetch)
        }
        do {
            let result = task!.value
            task = nil
            return result
        }
        catch {
            task = nil
            throw error
        }
    }
}

// Then a singleton can be defined for a specific endpoint and result type:

let mux = Multiplexer<MyObject>(onFetch: myBackendCall)

This works fine as long as Multiplexer and its singleton instance are MainActor-isolated. However, noticing how SwiftUI can spawn threads e.g. in the .task() view modifier where I typically make backend requests in my app, I'm now thinking I could benefit from it and use concurrency in full.

A full implementation of Multiplexer and similar interfaces in my library contain dictionaries, e.g. an interface that retrieves media files caches them in a dictionary hashed by URL. Without MainActor isolation I had crashes when accessing this dictionary (and no warning from the compiler!). But even a simpler property like task above is not protected and can cause problems when accessed concurrently.

My question is: is there a better pattern where I could get rid of the MainActor requirement given that there are shared states cruicial for Multiplexer's functionality?

(The attempt to rewrite the Multiplexer library with async/await can be found here.)