This is no different to doing what you normally do for driving 7-segment displays.
Digits are first completely blanked, then the proper segment information for the current digit is presented, then that digit is enabled. This goes on for every digit, for all digits. One digit lights at a time and the whole cycle has to be performed at a frequency higher than what the human eye perceives, depending on the application. For normal cheap devices standing still on a desk you can use above 50Hz, preferably 100Hz. For other applications perhaps you’d have to follow some regulation indicating higher frequencies.
Obviously you will not wait in a loop for 20ms, you either fire an interrupt or set up a task or periodically request a timer event. A four-digit display updated at 50 Hz means 4x50=200Hz = do it every 5ms.
Your application never writes to the display, it stores to memory and the code driving the display does that.
If you will be performing animations, you have to sync your updates to a full display refresh, in order to avoid ghosting and artifacts. In this case, an irregular update frequency might cause some tearing in the movement, in which case I would favor interrupts.
It is always preferred to defer updating the display to a full display refresh, if you perform periodic writings anytime there will be a clash between app update frequency and display update frequency and some ghosting or blinking may appear.
I wrote this in 68HC08 assembly 20+ years ago and ported to several other microcontrollers, and to C. It is working nice in many devices. I always use a hardware timer interrupt for this activity since I mostly work on bare metal (no OS). I set a flag when the driver has finished updating the last digit and the app stores desired value before first digit update begins. More practical and elegant solutions can be used on something like mOS, for example, like a callback…