Producer and consumer can communicate in 2 ways: synchronous and asynchronous.
In synchronous (pull-based) way, consumer is a thread and some intermediate communicator object is used. Usually it is a blocking queue. In special case, when only single value is passed during the whole producer-consumer communication, a communicator which implements interface Future can be used. This way is called synchronous, because the consumer calls communicating method like Future.get() and that methods waits until the value is available, and then returns that value as a result. That is, requesting the value, and receiving it, are programmed in the same statement, though these actions can be separated in time.
The drawback of synchronous communication is that when the consumer waits for the requested value, it wastes considerable amount of memory for it's thread stack. As a result, we can have only limited number of actions which wait for data. For example, it could be internet connections serving multiple clients. To increase that number, we can represent consumer not as a thread, but as some relatively small object, with methods called by the producer or communicator when datum for consumer is available. This way is called asynchronous. It is split in 2 actions: request to producer to pass data and passing that data to consumer. This is asynchronous (push-based) method.
Now the reply to the question is: Future is able to act as a synchronous communicator only (with get methods), and Mono can be used both as synchronous communicator (with block methods) and as an asynchronous one (with subscribe methods).
Note that java.util.concurrent.CompletableFuture can also act both as synchronous and asynchronous communicator. Why to have similar means to do the same thing? This phenomenon is called not invented here.