Java Code Examples for reactor.core.scheduler.Schedulers#newSingle()
The following examples show how to use
reactor.core.scheduler.Schedulers#newSingle() .
You can vote up the ones you like or vote down the ones you don't like,
and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example 1
Source File: EmployeeServiceImpl.java From Spring-5.0-Cookbook with MIT License | 6 votes |
@Override public Flux<Employee> readEmployeesByAscLastName() { Scheduler subWorker = Schedulers.newSingle("sub-thread"); Scheduler pubWorker = Schedulers.newSingle("pub-thread"); Supplier<Flux<Employee>> deferredTask = ()->{ System.out.println("flux:defer task executor: " + Thread.currentThread().getName()); System.out.println("flux:defer task executor login: " + SecurityContextHolder.getContext().getAuthentication().getPrincipal()); return Flux.fromIterable(employeeDaoImpl.getEmployees()); }; Comparator<Employee> descLName = (e1, e2) -> { System.out.println("flux:sort task executor: " + Thread.currentThread().getName()); System.out.println("flux:sort task executor login: " + SecurityContextHolder.getContext().getAuthentication().getPrincipal()); return e1.getLastName().compareTo(e2.getLastName()); }; Flux<Employee> deferred = Flux.defer(deferredTask).sort(descLName).subscribeOn(subWorker).publishOn(pubWorker); return deferred; }
Example 2
Source File: EmployeeServiceImpl.java From Spring-5.0-Cookbook with MIT License | 6 votes |
@Override public Flux<Employee> readEmployeesByDescAge() { Scheduler subWorker = Schedulers.newSingle("sub-thread"); Scheduler pubWorker = Schedulers.newSingle("pub-thread"); Supplier<Flux<Employee>> deferredTask = ()->{ System.out.println("flux:defer task executor: "+ Thread.currentThread().getName()); System.out.println("flux:defer task executor login: " + SecurityContextHolder.getContext().getAuthentication().getPrincipal()); return Flux.fromIterable(employeeDaoImpl.getEmployees()); }; Comparator<Employee> descAge = (e1, e2) -> { System.out.println("flux:sort task executor: " + Thread.currentThread().getName()); System.out.println("flux:sort task executor login: " + SecurityContextHolder.getContext().getAuthentication().getPrincipal()); if(e1.getAge().compareTo(e2.getAge()) == 0){ return 0; } else if(e1.getAge().compareTo(e2.getAge()) > 0){ return -1; } else return 1; }; Flux<Employee> deferred = Flux.defer(deferredTask).sort(descAge).subscribeOn(subWorker).publishOn(pubWorker); return deferred; }
Example 3
Source File: SimpleLifoPoolTest.java From reactor-pool with Apache License 2.0 | 6 votes |
@Test void consistentThreadDeliveringWhenHasElements() throws InterruptedException { Scheduler deliveryScheduler = Schedulers.newSingle("delivery"); AtomicReference<String> threadName = new AtomicReference<>(); Scheduler acquireScheduler = Schedulers.newSingle("acquire"); PoolConfig<PoolableTest> testConfig = poolableTestConfig(1, 1, Mono.fromCallable(PoolableTest::new) .subscribeOn(Schedulers.newParallel("poolable test allocator")), deliveryScheduler); SimpleLifoPool<PoolableTest> pool = new SimpleLifoPool<>(testConfig); //the pool is started with one available element //we prepare to acquire it Mono<PoolableTest> borrower = Mono.fromDirect(pool.withPoolable(Mono::just)); CountDownLatch latch = new CountDownLatch(1); //we actually request the acquire from a separate thread and see from which thread the element was delivered acquireScheduler.schedule(() -> borrower.subscribe(v -> threadName.set(Thread.currentThread().getName()), e -> latch.countDown(), latch::countDown)); latch.await(1, TimeUnit.SECONDS); assertThat(threadName.get()) .startsWith("delivery-"); }
Example 4
Source File: EmployeeServiceImpl.java From Spring-5.0-Cookbook with MIT License | 6 votes |
@Override public Flux<Employee> readEmployeesFlux(int age) { Scheduler subWorker = Schedulers.newSingle("sub-thread"); Scheduler pubWorker = Schedulers.newSingle("pub-thread"); Predicate<Employee> validAge = (e) -> { System.out.println("flux:filter task executor: " + Thread.currentThread().getName()); System.out.println("flux:filter task executor login: " + SecurityContextHolder.getContext().getAuthentication().getPrincipal()); return e.getAge() > age; }; Supplier<Flux<Employee>> deferredTask = ()->{ System.out.println("flux:defer task executor: " + Thread.currentThread().getName()); System.out.println("flux:defer task executor login: " + SecurityContextHolder.getContext().getAuthentication().getPrincipal()); return Flux.fromIterable(employeeDaoImpl.getEmployees()); }; Flux<Employee> deferred = Flux.defer(deferredTask).filter(validAge).subscribeOn(subWorker).publishOn(pubWorker); return deferred; }
Example 5
Source File: SimpleLifoPoolTest.java From reactor-pool with Apache License 2.0 | 6 votes |
@Test void consistentThreadDeliveringWhenNoElementsButNotFull() throws InterruptedException { Scheduler deliveryScheduler = Schedulers.newSingle("delivery"); AtomicReference<String> threadName = new AtomicReference<>(); Scheduler acquireScheduler = Schedulers.newSingle("acquire"); PoolConfig<PoolableTest> testConfig = poolableTestConfig(0, 1, Mono.fromCallable(PoolableTest::new) .subscribeOn(Schedulers.newParallel("poolable test allocator")), deliveryScheduler); SimpleLifoPool<PoolableTest> pool = new SimpleLifoPool<>(testConfig); //the pool is started with no elements, and has capacity for 1 //we prepare to acquire, which would allocate the element Mono<PoolableTest> borrower = Mono.fromDirect(pool.withPoolable(Mono::just)); CountDownLatch latch = new CountDownLatch(1); //we actually request the acquire from a separate thread, but the allocation also happens in a dedicated thread //we look at which thread the element was delivered from acquireScheduler.schedule(() -> borrower.subscribe(v -> threadName.set(Thread.currentThread().getName()), e -> latch.countDown(), latch::countDown)); latch.await(1, TimeUnit.SECONDS); assertThat(threadName.get()) .startsWith("delivery-"); }
Example 6
Source File: SimpleFifoPoolTest.java From reactor-pool with Apache License 2.0 | 6 votes |
@Test void defaultThreadDeliveringWhenHasElements() throws InterruptedException { AtomicReference<String> threadName = new AtomicReference<>(); Scheduler acquireScheduler = Schedulers.newSingle("acquire"); PoolConfig<PoolableTest> testConfig = poolableTestConfig(1, 1, Mono.fromCallable(PoolableTest::new) .subscribeOn(Schedulers.newParallel("poolable test allocator"))); SimpleFifoPool<PoolableTest> pool = new SimpleFifoPool<>(testConfig); pool.warmup().block(); //the pool is started and warmed up with one available element //we prepare to acquire it Mono<PooledRef<PoolableTest>> borrower = pool.acquire(); CountDownLatch latch = new CountDownLatch(1); //we actually request the acquire from a separate thread and see from which thread the element was delivered acquireScheduler.schedule(() -> borrower.subscribe(v -> threadName.set(Thread.currentThread().getName()), e -> latch.countDown(), latch::countDown)); latch.await(1, TimeUnit.SECONDS); assertThat(threadName.get()) .startsWith("acquire-"); }
Example 7
Source File: SimpleLifoPoolTest.java From reactor-pool with Apache License 2.0 | 6 votes |
@Test void defaultThreadDeliveringWhenNoElementsButNotFull() throws InterruptedException { AtomicReference<String> threadName = new AtomicReference<>(); Scheduler acquireScheduler = Schedulers.newSingle("acquire"); PoolConfig<PoolableTest> testConfig = poolableTestConfig(0, 1, Mono.fromCallable(PoolableTest::new) .subscribeOn(Schedulers.newParallel("poolable test allocator"))); SimpleLifoPool<PoolableTest> pool = new SimpleLifoPool<>(testConfig); //the pool is started with no elements, and has capacity for 1 //we prepare to acquire, which would allocate the element Mono<PooledRef<PoolableTest>> borrower = pool.acquire(); CountDownLatch latch = new CountDownLatch(1); //we actually request the acquire from a separate thread, but the allocation also happens in a dedicated thread //we look at which thread the element was delivered from acquireScheduler.schedule(() -> borrower.subscribe(v -> threadName.set(Thread.currentThread().getName()), e -> latch.countDown(), latch::countDown)); latch.await(1, TimeUnit.SECONDS); assertThat(threadName.get()) .startsWith("poolable test allocator-"); }
Example 8
Source File: SimpleFifoPoolTest.java From reactor-pool with Apache License 2.0 | 6 votes |
@Test void consistentThreadDeliveringWhenHasElements() throws InterruptedException { Scheduler deliveryScheduler = Schedulers.newSingle("delivery"); AtomicReference<String> threadName = new AtomicReference<>(); Scheduler acquireScheduler = Schedulers.newSingle("acquire"); PoolConfig<PoolableTest> testConfig = poolableTestConfig(1, 1, Mono.fromCallable(PoolableTest::new) .subscribeOn(Schedulers.newParallel("poolable test allocator")), deliveryScheduler); SimpleFifoPool<PoolableTest> pool = new SimpleFifoPool<>(testConfig); //the pool is started with one available element //we prepare to acquire it Mono<PooledRef<PoolableTest>> borrower = pool.acquire(); CountDownLatch latch = new CountDownLatch(1); //we actually request the acquire from a separate thread and see from which thread the element was delivered acquireScheduler.schedule(() -> borrower.subscribe(v -> threadName.set(Thread.currentThread().getName()), e -> latch.countDown(), latch::countDown)); latch.await(1, TimeUnit.SECONDS); assertThat(threadName.get()) .startsWith("delivery-"); }
Example 9
Source File: EmployeeScheduledStreamServiceImpl.java From Spring-5.0-Cookbook with MIT License | 5 votes |
@Override public Flux<Employee> createPubAndMain() { Scheduler pubWorker = Schedulers.newSingle("pub-thread"); Predicate<Employee> validAge = (e) -> { System.out.println("filter thread " +Thread.currentThread().getName()); return e.getAge() > 25; }; Supplier<Flux<Employee>> deferredTask = ()->{ System.out.println("defer thread "+Thread.currentThread().getName()); return Flux.fromIterable(employeeDaoImpl.getEmployees()); }; Flux<Employee> deferred = Flux.defer(deferredTask).publishOn(pubWorker).filter(validAge); return deferred; }
Example 10
Source File: FluxBufferTimeoutTest.java From reactor-core with Apache License 2.0 | 5 votes |
@Test public void rejectedOnNextLeadsToOnError() { Scheduler scheduler = Schedulers.newSingle("rejectedOnNextLeadsToOnError"); scheduler.dispose(); StepVerifier.create(Flux.just(1, 2, 3) .bufferTimeout(4, Duration.ofMillis(500), scheduler)) .expectError(RejectedExecutionException.class) .verify(Duration.ofSeconds(1)); }
Example 11
Source File: SimpleFifoPoolTest.java From reactor-pool with Apache License 2.0 | 5 votes |
@Test void consistentThreadDeliveringWhenNoElementsAndFull() throws InterruptedException { Scheduler deliveryScheduler = Schedulers.newSingle("delivery"); AtomicReference<String> threadName = new AtomicReference<>(); Scheduler acquireScheduler = Schedulers.newSingle("acquire"); Scheduler releaseScheduler = Schedulers.fromExecutorService( Executors.newSingleThreadScheduledExecutor((r -> new Thread(r,"release")))); PoolConfig<PoolableTest> testConfig = poolableTestConfig(1, 1, Mono.fromCallable(PoolableTest::new) .subscribeOn(Schedulers.newParallel("poolable test allocator")), deliveryScheduler); SimpleFifoPool<PoolableTest> pool = new SimpleFifoPool<>(testConfig); //the pool is started with one elements, and has capacity for 1. //we actually first acquire that element so that next acquire will wait for a release PooledRef<PoolableTest> uniqueSlot = pool.acquire().block(); assertThat(uniqueSlot).isNotNull(); //we prepare next acquire Mono<PooledRef<PoolableTest>> borrower = pool.acquire(); CountDownLatch latch = new CountDownLatch(1); //we actually perform the acquire from its dedicated thread, capturing the thread on which the element will actually get delivered acquireScheduler.schedule(() -> borrower.subscribe(v -> threadName.set(Thread.currentThread().getName()), e -> latch.countDown(), latch::countDown)); //after a short while, we release the acquired unique element from a third thread releaseScheduler.schedule(uniqueSlot.release()::block, 500, TimeUnit.MILLISECONDS); latch.await(1, TimeUnit.SECONDS); assertThat(threadName.get()) .startsWith("delivery-"); }
Example 12
Source File: SimpleLifoPoolTest.java From reactor-pool with Apache License 2.0 | 5 votes |
@Test void consistentThreadDeliveringWhenNoElementsAndFull() throws InterruptedException { Scheduler deliveryScheduler = Schedulers.newSingle("delivery"); AtomicReference<String> threadName = new AtomicReference<>(); Scheduler acquireScheduler = Schedulers.newSingle("acquire"); Scheduler releaseScheduler = Schedulers.fromExecutorService( Executors.newSingleThreadScheduledExecutor((r -> new Thread(r,"release")))); PoolConfig<PoolableTest> testConfig = poolableTestConfig(1, 1, Mono.fromCallable(PoolableTest::new) .subscribeOn(Schedulers.newParallel("poolable test allocator")), deliveryScheduler); SimpleLifoPool<PoolableTest> pool = new SimpleLifoPool<>(testConfig); //the pool is started with one elements, and has capacity for 1. //we actually first acquire that element so that next acquire will wait for a release PooledRef<PoolableTest> uniqueSlot = pool.acquire().block(); assertThat(uniqueSlot).isNotNull(); //we prepare next acquire Mono<PoolableTest> borrower = Mono.fromDirect(pool.withPoolable(Mono::just)); CountDownLatch latch = new CountDownLatch(1); //we actually perform the acquire from its dedicated thread, capturing the thread on which the element will actually get delivered acquireScheduler.schedule(() -> borrower.subscribe(v -> threadName.set(Thread.currentThread().getName()), e -> latch.countDown(), latch::countDown)); //after a short while, we release the acquired unique element from a third thread releaseScheduler.schedule(uniqueSlot.release()::block, 500, TimeUnit.MILLISECONDS); latch.await(1, TimeUnit.SECONDS); assertThat(threadName.get()) .startsWith("delivery-"); }
Example 13
Source File: LeaderActivationCoordinator.java From titus-control-plane with Apache License 2.0 | 4 votes |
/** * @param services list of services to activate in the desired activation order */ public LeaderActivationCoordinator(LeaderActivationConfiguration configuration, List<LeaderActivationListener> services, Consumer<Throwable> deactivationCallback, ClusterMembershipService membershipService, TitusRuntime titusRuntime) { this.configuration = configuration; this.services = services; this.deactivationCallback = deactivationCallback; this.membershipService = membershipService; this.localMemberId = membershipService.getLocalClusterMember().getCurrent().getMemberId(); this.clock = titusRuntime.getClock(); this.registry = titusRuntime.getRegistry(); this.stateMetricFsm = SpectatorExt.fsmMetrics( registry.createId(METRIC_ROOT + "state"), s -> s == State.Deactivated, State.Awaiting, registry ); this.inActiveStateTimeId = registry.createId(METRIC_ROOT + "inActiveStateTime"); PolledMeter.using(registry).withId(inActiveStateTimeId).monitorValue(this, self -> (self.stateRef.get() == State.ElectedLeader && activationTimestamp > 0) ? self.clock.wallTime() - self.activationTimestamp : 0 ); // We create the thread here, as the default one is NonBlocking, and we allow React blocking subscriptions in // the activation phase. this.scheduler = Schedulers.newSingle(r -> { Thread thread = new Thread(r, "LeaderActivationCoordinator"); thread.setDaemon(true); return thread; }); this.scheduleRef = titusRuntime.getLocalScheduler().scheduleMono( SCHEDULE_DESCRIPTOR.toBuilder() .withInterval(Duration.ofMillis(configuration.getLeaderCheckIntervalMs())) .withTimeout(Duration.ofMillis(configuration.getLeaderActivationTimeout())) .build(), context -> refresh(), scheduler ); }
Example 14
Source File: LoginHandler.java From Spring-5.0-Cookbook with MIT License | 4 votes |
public Mono<ServerResponse> loginDetailsById(ServerRequest req) { Scheduler subWorker = Schedulers.newSingle("sub-thread"); Mono<LoginDetails> login = Mono.defer(() -> Mono.justOrEmpty(logindetailsServiceImpl.findLoginById(Integer.parseInt(req.pathVariable("id"))))).subscribeOn(subWorker); return ok().contentType(MediaType.APPLICATION_STREAM_JSON).body(login, LoginDetails.class) .switchIfEmpty(ServerResponse.notFound().build()); }
Example 15
Source File: DeptDataHandler.java From Spring-5.0-Cookbook with MIT License | 4 votes |
public Mono<ServerResponse> saveDepartmentMono(ServerRequest req) { Scheduler subWorker = Schedulers.newSingle("sub-thread"); Mono<Department> department = req.bodyToMono(Department.class).doOnNext(departmentServiceImpl::saveDeptRec).subscribeOn(subWorker); return ok().contentType(MediaType.APPLICATION_STREAM_JSON).build(department.then()); }
Example 16
Source File: SimpleFifoPoolTest.java From reactor-pool with Apache License 2.0 | 4 votes |
void consistentThreadDeliveringWhenNoElementsAndFullAndRaceDrain(int i) throws InterruptedException { Scheduler deliveryScheduler = Schedulers.newSingle("delivery"); AtomicReference<String> threadName = new AtomicReference<>(); AtomicInteger newCount = new AtomicInteger(); Scheduler acquire1Scheduler = Schedulers.newSingle("acquire1"); Scheduler racerReleaseScheduler = Schedulers.fromExecutorService( Executors.newSingleThreadScheduledExecutor((r -> new Thread(r,"racerRelease")))); Scheduler racerAcquireScheduler = Schedulers.newSingle("racerAcquire"); PoolConfig<PoolableTest> testConfig = poolableTestConfig(1, 1, Mono.fromCallable(() -> new PoolableTest(newCount.getAndIncrement())) .subscribeOn(Schedulers.newParallel("poolable test allocator")), deliveryScheduler); SimpleFifoPool<PoolableTest> pool = new SimpleFifoPool<>(testConfig); //the pool is started with one elements, and has capacity for 1. //we actually first acquire that element so that next acquire will wait for a release PooledRef<PoolableTest> uniqueSlot = pool.acquire().block(); assertThat(uniqueSlot).isNotNull(); //we prepare next acquire Mono<PooledRef<PoolableTest>> borrower = pool.acquire(); CountDownLatch latch = new CountDownLatch(1); //we actually perform the acquire from its dedicated thread, capturing the thread on which the element will actually get delivered acquire1Scheduler.schedule(() -> borrower.subscribe(v -> threadName.set(Thread.currentThread().getName()) , e -> latch.countDown(), latch::countDown)); //in parallel, we'll both attempt a second acquire AND release the unique element (each on their dedicated threads Mono<PooledRef<PoolableTest>> otherBorrower = pool.acquire(); racerAcquireScheduler.schedule(() -> otherBorrower.subscribe().dispose(), 100, TimeUnit.MILLISECONDS); racerReleaseScheduler.schedule(uniqueSlot.release()::block, 100, TimeUnit.MILLISECONDS); latch.await(1, TimeUnit.SECONDS); //we expect that, consistently, the poolable is delivered on a `delivery` thread assertThat(threadName.get()).as("round #" + i).startsWith("delivery-"); //we expect that only 1 element was created assertThat(newCount).as("elements created in round " + i).hasValue(1); }
Example 17
Source File: FluxTests.java From reactor-core with Apache License 2.0 | 4 votes |
/** * <pre> * forkStream * / \ < - - - int * v v * persistenceStream computationStream * \ / < - - - List< String > * v v * joinStream < - - - String * splitStream * observedSplitStream * </pre> * @throws Exception for convenience */ @Test(timeout = TIMEOUT) public void multiplexUsingDispatchersAndSplit() throws Exception { final FluxIdentityProcessor<Integer> forkEmitterProcessor = Processors.multicast(); final FluxIdentityProcessor<Integer> computationEmitterProcessor = Processors.more().multicast(false); Scheduler computation = Schedulers.newSingle("computation"); Scheduler persistence = Schedulers.newSingle("persistence"); Scheduler forkJoin = Schedulers.newParallel("forkJoin", 2); final Flux<List<String>> computationStream = computationEmitterProcessor.publishOn(computation) .map(i -> { final List<String> list = new ArrayList<>(i); for (int j = 0; j < i; j++) { list.add("i" + j); } return list; }) .doOnNext(ls -> println("Computed: ", ls)) .log("computation"); final FluxIdentityProcessor<Integer> persistenceEmitterProcessor = Processors.more().multicast(false); final Flux<List<String>> persistenceStream = persistenceEmitterProcessor.publishOn(persistence) .doOnNext(i -> println("Persisted: ", i)) .map(i -> Collections.singletonList("done" + i)) .log("persistence"); Flux<Integer> forkStream = forkEmitterProcessor.publishOn(forkJoin) .log("fork"); forkStream.subscribe(computationEmitterProcessor); forkStream.subscribe(persistenceEmitterProcessor); final Flux<List<String>> joinStream = Flux.zip(computationStream, persistenceStream, (a, b) -> Arrays.asList(a, b)) .publishOn(forkJoin) .map(listOfLists -> { listOfLists.get(0) .addAll(listOfLists.get(1)); return listOfLists.get(0); }) .log("join"); final Semaphore doneSemaphore = new Semaphore(0); final MonoProcessor<List<String>> listPromise = joinStream.flatMap(Flux::fromIterable) .log("resultStream") .collectList() .doOnTerminate(doneSemaphore::release) .toProcessor(); listPromise.subscribe(); forkEmitterProcessor.onNext(1); forkEmitterProcessor.onNext(2); forkEmitterProcessor.onNext(3); forkEmitterProcessor.onComplete(); List<String> res = listPromise.block(Duration.ofSeconds(5)); assertEquals(Arrays.asList("i0", "done1", "i0", "i1", "done2", "i0", "i1", "i2", "done3"), res); forkJoin.dispose(); persistence.dispose(); computation.dispose(); }
Example 18
Source File: DeptDataHandler.java From Spring-5.0-Cookbook with MIT License | 4 votes |
public Mono<ServerResponse> saveDepartmentMono(ServerRequest req) { Scheduler subWorker = Schedulers.newSingle("sub-thread"); Mono<Department> department = req.bodyToMono(Department.class).doOnNext(departmentServiceImpl::saveDeptRec).subscribeOn(subWorker); return ok().contentType(MediaType.APPLICATION_STREAM_JSON).build(department.then()); }
Example 19
Source File: LoginHandler.java From Spring-5.0-Cookbook with MIT License | 4 votes |
public Mono<ServerResponse> saveUserdetailsMono(ServerRequest req) { Scheduler subWorker = Schedulers.newSingle("sub-thread"); Mono<UserDetails> loginDetails = req.bodyToMono(UserDetails.class).doOnNext(userdetailsServiceImpl::saveUserdetails).subscribeOn(subWorker); return ok().contentType(MediaType.APPLICATION_STREAM_JSON).build(loginDetails.then()); }
Example 20
Source File: SimpleLifoPoolTest.java From reactor-pool with Apache License 2.0 | 4 votes |
void consistentThreadDeliveringWhenNoElementsAndFullAndRaceDrain(int i) throws InterruptedException { Scheduler allocatorScheduler = Schedulers.newParallel("poolable test allocator"); Scheduler deliveryScheduler = Schedulers.newSingle("delivery"); Scheduler acquire1Scheduler = Schedulers.newSingle("acquire1"); Scheduler racerScheduler = Schedulers.fromExecutorService( Executors.newFixedThreadPool(2, (r -> new Thread(r,"racer")))); try { AtomicReference<String> threadName = new AtomicReference<>(); AtomicInteger newCount = new AtomicInteger(); PoolConfig<PoolableTest> testConfig = poolableTestConfig(1, 1, Mono.fromCallable(() -> new PoolableTest(newCount.getAndIncrement())) .subscribeOn(allocatorScheduler), deliveryScheduler); SimpleLifoPool<PoolableTest> pool = new SimpleLifoPool<>(testConfig); //the pool is started with one elements, and has capacity for 1. //we actually first acquire that element so that next acquire will wait for a release PooledRef<PoolableTest> uniqueSlot = pool.acquire().block(); assertThat(uniqueSlot).isNotNull(); //we prepare next acquire Mono<PoolableTest> firstBorrower = Mono.fromDirect(pool.withPoolable(Mono::just)); Mono<PoolableTest> otherBorrower = Mono.fromDirect(pool.withPoolable(Mono::just)); CountDownLatch latch = new CountDownLatch(3); //we actually perform the acquire from its dedicated thread, capturing the thread on which the element will actually get delivered acquire1Scheduler.schedule(() -> firstBorrower.subscribe(v -> threadName.set(Thread.currentThread().getName()) , e -> latch.countDown(), latch::countDown)); //in parallel, we'll race a second acquire AND release the unique element (each on their dedicated threads) //since LIFO we expect that if the release loses, it will server acquire1 RaceTestUtils.race( () -> otherBorrower.subscribe(v -> threadName.set(Thread.currentThread().getName()) , e -> latch.countDown(), latch::countDown), () -> { uniqueSlot.release().block(); latch.countDown(); }, racerScheduler); latch.await(1, TimeUnit.SECONDS); //we expect that, consistently, the poolable is delivered on a `delivery` thread assertThat(threadName.get()).as("round #" + i).startsWith("delivery-"); //2 elements MIGHT be created if the first acquire wins (since we're in auto-release mode) assertThat(newCount.get()).as("1 or 2 elements created in round " + i).isIn(1, 2); } finally { allocatorScheduler.dispose(); deliveryScheduler.dispose(); acquire1Scheduler.dispose(); racerScheduler.dispose(); } }