Game Loops

This subject has been touched on in other threads, particularly in the Articles & Tutorials sections, which I’ve looked through (and based my code on in fact). From what I understood, Timer (either util or Swing) is a bad idea for animation due to their lack of reliabile updating mechanisms. The seemingly “de facto” way is to use System.nanoTime() and compute your update and render time, accounting for the difference (whether fast or slow). It’s a sound method, and I’m understanding it the more I read.

I have two classes, GameLoop and GameWindow. I didn’t bother with a Canvas because java.awt.Window also implements a bufferstrategy and decided to forego adding an extra object/class to my code. Here is the relevant source:

import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

import javax.swing.SwingUtilities;

public class GameLoop {
	
	public static final long FRAME_INTERVAL = 41;	// Equivalent to 24 frames per second
	
	public static void main(String[] args) {
		
		SwingUtilities.invokeLater(new Runnable() {

			@Override
			public void run() {
				
				final GameWindow window = new GameWindow();
				
				Executors.newSingleThreadScheduledExecutor().scheduleWithFixedDelay(
						new Runnable(){
							
							@Override
							public void run() {
								
								window.update();	// Perform update
								window.repaint();
							}
						}, 0L, FRAME_INTERVAL, TimeUnit.MILLISECONDS);
			}
			
		});
	}
}
import java.awt.Graphics;
import java.awt.GraphicsEnvironment;
import java.awt.HeadlessException;
import java.awt.Window;
import java.awt.event.WindowEvent;
import java.awt.event.WindowListener;

@SuppressWarnings("serial")
public class GameWindow extends Window {
	
	private int x = 0;
	
	GameWindow() throws HeadlessException {
		
		super(null, GraphicsEnvironment.getLocalGraphicsEnvironment().getDefaultScreenDevice().getDefaultConfiguration());
		
		if(!getGraphicsConfiguration().getDevice().isFullScreenSupported()) {
			
			System.out.println("Your device does not support full screen exclusive mode");
			System.exit(0);
		}
		
		addWindowListener(new WindowListener() {

			@Override
			public void windowOpened(WindowEvent e) {}

			@Override
			public void windowClosing(WindowEvent e) {
				
				getGraphicsConfiguration().getDevice().setFullScreenWindow(null);
				dispose();
			}

			@Override
			public void windowClosed(WindowEvent e) {}

			@Override
			public void windowIconified(WindowEvent e) {}

			@Override
			public void windowDeiconified(WindowEvent e) {}

			@Override
			public void windowActivated(WindowEvent e) {
				
				requestFocus();
			}

			@Override
			public void windowDeactivated(WindowEvent e) {}
			
			
		});
		
		setBounds(getGraphicsConfiguration().getBounds());
		setLayout(null);
		setIgnoreRepaint(true);
		getGraphicsConfiguration().getDevice().setFullScreenWindow(this);	// Show full screen window
		createBufferStrategy(2);
	}
	
	@Override
	public void repaint() {
		
		Graphics g = getBufferStrategy().getDrawGraphics();
		g.clearRect(0, 0, getWidth(), getHeight());
		paint(g);
		g.dispose();
		getBufferStrategy().show();	// Display the new graphics onto the canvas
		getToolkit().sync();
	}
	
	@Override
	public void paint(Graphics g) {
		
		g.fillRect(x, 0, 20, 20);
	}
	
	public void update(){
		
		x += x < 500 ? 5 : -500; 
	}
}

This works and all it does is paint a simple rectangle that moves along the upper portion of the screen. Nothing spectacular really, just something to help me get a grasp on thing.

My questions are the following:
Is it “wrong” to use an executor in this manner?
Is the executor a reliable timing mechanism?
As the next frame only executes once the prior frame has ended (due to the single thread scheduled execution) am I correct in assuming my frame rate is variable?
If the window.update() and window.render() finish prematurely, does the scheduler perform the equivalent waiting of Thread.sleep automatically?

The purpose of this is to develop some sort of reliable skeleton framework for animated games, that I understand and that isn’t just a copy/paste of someone else’s code. Use of an Executor in his fashion may obviously not be the best practice or an extremely obtuse or preposterous way of doing things as I haven’t seen it elsewhere (and there’s likely a reason for that). Any help or critiques about this code are welcome. Thanks for your input.