Hi Daniel,
great to see you use the Codec API.
lettuce is internally fully asynchronous, and the API is thread-safe. You can use one connection for all your operations by multiple threads as long as you don't use transactions or blocking operations.
Multiple calls on one connection are pipelined, meaning the preceding command does not need to be finished at the time you invoke the next command. This is true for the sync and the async API.
While you cannot invoke two commands at the same time using the sync API (from one thread), you can do so by using one connection (with the sync API) by two threads. This means that synchronicity is only visible to the calling thread but not to the full application.
Redis works single-threaded but there are cases where you set a value, then get it (on two different threads), and the set is not fully finished.
If you need _full_ synchronization, you need to synchronize access to the connection on your own. That all above applies when using one connection with one/multiple threads.
The connection pool creates multiple connections and, in that case, every connection is used by just one thread (as far as I can see). In that case, multiple threads can perform truly asynchronous operations that send multiple commands at a time by using different connections. Redis then performs the synchronization.
The synchronous aspect applies only on thread-level, never globally. Other clients, that do connection pooling usually run into the same issue, since you have multiple decoupled connections.
Please come back to me, if you have questions or issues. The whole sync/async thing can be quite confusing.
HTH, Mark