So I've implemented a screen manager in Dolce that does just that -- maintains a stack of game screens, any of which may be active or suspended, and loops through the stack each frame, calling a tick method on the ones that are active. The implementation is based on one by James Boer from Game Programming Gems 5, one that I have implemented so many times I can do it blindfolded now.
First, you register a screen under a unique name of your choosing. When you are ready to activate it, you issue a push command to the screen manager. Internally, when a screen is pushed onto the stack, its init method is called. Then it is eligible to be ticked each time the screen manager's tick runs. It can push other screens on top of itself without interrupting any current tick processing, as all stack commands are delayed until the next time the screen manager ticks. When another screen is pushed onto the stack, the pause method is called on the screen at the top. When a screen is popped, its term method is called. And when a screen becomes the new top as the result of a pop, its resume method is called.
One aspect of the system that gives it flexibility is that whenever a stack command is issued, the name of a particular screen is passed to the lifecycle method being called. A screen's init method is given the name of the screen which it is being pushed on top of, its pause method the name of the screen which is pushed on top of it, its resume method the name of the screen popped off of it, and its term method the name of the screen beneath it. This allows you to do things like use the same instance in multiple places on the stack.
As an example, consider a game's main menu. You will show it once at game start up. Let's say the player selects 'PLAY NOW'. Now, the main menu screen pushes the game play screen, and the screen manager calls the pause method on the main menu, giving it the name of the game play screen as an argument. Since the main menu knows it pushed the game play screen on top of itself, it can check the name to recognize that the game play screen is active. Later, the player presses the escape key to see the main menu again. So, the game play screen issues a push command to the screen manager, giving it the registered name of the main menu. The main menu instance, the same one already on the bottom of the stack, is fetched again from the registry and its init command called with the name of the game play screen. It realizes it is already initialized and was paused. So, instead of pausing, it simply resumes. You obviously don't want to display 'PLAY NOW' when the player is already playing, so you verify that the name given to the init method matches the game play screen's name and change the text on the button, and its corresponding action, to 'RESUME GAME'. Everything else stays the same. When that button is clicked, the main menu pops itself off the stack. When the pop command is executed, its term method is called with the name of the game play screen. By checking the name, the main menu realizes it's not really time to terminate yet, so pauses instead. Game play resumes.
Anyway, it's a really basic system that gives several options for handling game states. You can instantiate as many screen managers as you want. No, it isn't a singleton. I figure there are use-cases for multiple screen managers. Consider an in-game editor. I think it'd be more appropriate to have separate managers going -- one for the game and one for the editor -- than trying to manage everything on one stack. You wouldn't always want to terminate the editor when switching into game mode. Instead, you just switch between the screen managers.