Design isolation for a service that calls three downstream dependencies, one of which (a third-party pricing API) is known to be flaky. Compare a dedicated thread-pool bulkhead per dependency against a semaphore bulkhead on a shared pool, and say which actually contains a slow — not just failing — pricing API.
The cascading-failure mechanism this is defending against is specific: a resource shared by unrelated work — here, a thread pool — gets filled by calls to the one dependency that's struggling, and healthy calls to the other two dependencies start queuing or failing behind it, even though they never touch the pricing API at all. A thread-pool bulkhead removes the word "shared": give the pricing API its own dedicated, bounded ThreadPoolExecutor with its own queue, sized to what that one dependency actually needs, so when it goes slow, only its own pool fills — calls to the other two dependencies run on their own pools and never queue behind pricing's stuck threads. A semaphore bulkhead is cheaper — it just caps how many concurrent calls to pricing are allowed on the shared pool, without a dedicated thread pool or queue to size — but it only limits concurrency, not how long a thread that's already calling pricing is tied up; if the timeout on that call is too long, a semaphore bulkhead still lets pricing's slow calls occupy shared-pool threads for the full timeout duration, just fewer of them at once. For a dependency that's specifically known to go slow rather than fail fast, the dedicated thread-pool bulkhead is the one that actually contains it.