Game loop taking around 30% of CPU

Hi, I was looking at the game loop tutorial and put it in a simple tile map based demo. I noticed that it consumes around 30% of the CPU. Is this value expected? Minecraft consumes exactly the same in my machine, but the game is much heavier. Just wondering if I could optimize my cpu consuption. Here is the code if anyone want to try, can run in window mode or applet.


import java.applet.Applet;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Image;
import java.awt.Rectangle;
import java.awt.Toolkit;
import java.awt.event.KeyEvent;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import java.awt.image.BufferedImage;
import java.net.URL;

import javax.imageio.ImageIO;

public class TileMap1 extends Applet implements Runnable {
	private static final int SCREEN_WIDTH = 8 * 32;
	private static final int SCREEN_HEIGHT = 7 * 32;
	private boolean isApplet;
	private Thread gameThread;
	private int fps;
	private BufferedImage tiles;
	private Image offImage;
	private int[][] myMap = { { 1, 1, 1, 1, 1, 1, 1, 1 }, //
			{ 1, 0, 0, 0, 0, 0, 0, 1 }, //
			{ 1, 0, 1, 0, 0, 0, 0, 1 }, //
			{ 1, 0, 0, 0, 0, 1, 0, 1 }, //
			{ 1, 0, 0, 0, 0, 0, 0, 2 }, //
			{ 1, 1, 1, 1, 1, 1, 1, 1 } };

	private int[][] myMap2 = { { 1, 1, 1, 1, 1, 1, 1, 1 }, //
			{ 1, 0, 0, 0, 0, 0, 0, 1 }, //
			{ 1, 0, 1, 0, 0, 0, 0, 1 }, //
			{ 1, 0, 0, 0, 0, 1, 0, 1 }, //
			{ 3, 0, 0, 0, 0, 0, 0, 1 }, //
			{ 1, 1, 1, 1, 1, 1, 1, 1 } };

	private int[][] currentMap;
	private Sprite hero;
	private boolean[] controls = new boolean[5];

	public TileMap1() {
		this.hero = new Sprite(2, 1);
		this.isApplet = true;
		this.currentMap = this.myMap;
		super.enableEvents(KeyEvent.KEY_EVENT_MASK);
	}

	public void init() {
		this.offImage = super.createImage(SCREEN_WIDTH, SCREEN_HEIGHT);
		try {
			URL url = this.getClass().getClassLoader().getResource("tiles.png");
			this.tiles = ImageIO.read(url);
		} catch (Exception e) {
			e.printStackTrace();
			System.exit(0);
		}
	}

	public void start() {
		if (this.gameThread == null) {
			this.gameThread = new Thread(this);
		}
		this.gameThread.start();
	}

	public void stop() {
		this.gameThread = null;
	}

	public void paint(Graphics g) {
		this.render(this.offImage.getGraphics());
		g.drawImage(this.offImage, 0, 0, 640, 480, null);

	}

	private void render(Graphics g) {
		g.setColor(Color.black);
		g.fillRect(0, 0, SCREEN_WIDTH, SCREEN_HEIGHT);

		// Draws our map.
		int mapWidth = this.currentMap[0].length;
		int mapHeight = this.currentMap.length;
		for (int i = 0; i < mapWidth; i++) {
			for (int j = 0; j < mapHeight; j++) {
				int frame = this.currentMap[j][i];
				g.drawImage(this.tiles.getSubimage(frame * 32, 0, 32, 32),
						i * 32, j * 32, null);
			}
		}

		hero.render(g);

		g.setColor(Color.red);
		g.drawString("FPS:" + this.fps, 10, 10);

	}

	public void run() {
		long lastLoopTime = System.nanoTime();
		final int TARGET_FPS = 60;
		final long OPTIMAL_TIME = 1000000000 / TARGET_FPS;
		long lastFpsTime = 0;
		int fps = 0;

		while (true) {
			long now = System.nanoTime();
			long updateLength = now - lastLoopTime;
			lastLoopTime = now;
			double delta = updateLength / ((double) OPTIMAL_TIME);

			// update the frame counter
			lastFpsTime += updateLength;
			fps++;
			// System.out.println(lastFpsTime);
			// update our FPS counter if a second has passed since
			// we last recorded
			if (lastFpsTime >= 1000000000) {
				// System.out.println("(FPS: " + fps + ")");
				this.fps = fps;
				lastFpsTime = 0;
				fps = 0;
			}

			this.logic();
			this.paint(this.getGraphics());
			Toolkit.getDefaultToolkit().sync();

			try {
				Thread.sleep((lastLoopTime - System.nanoTime() + OPTIMAL_TIME) / 1000000);
			} catch (Exception e) {
			}
		}
	}

	private void checkDoor(int j, int i) {
		if (this.currentMap[j][i] == 2) {
			this.currentMap = myMap2;
			hero.x = 1 * 32 + 6;
		} else if (this.currentMap[j][i] == 3) {
			this.currentMap = myMap;
			hero.x = 6 * 32 + 6;
		}
	}

	private void logic() {
		int dx = 0;
		int dy = 0;
		if (this.controls[0]) {
			dx = -1;
		} else if (this.controls[1]) {
			dx = 1;
		} else if (this.controls[2]) {
			dy = -1;
		} else if (this.controls[3]) {
			dy = 1;
		}
		hero.move(dx, dy);
	}

	protected void processKeyEvent(KeyEvent e) {
		int[] keys = new int[] { KeyEvent.VK_LEFT, KeyEvent.VK_RIGHT,
				KeyEvent.VK_UP, KeyEvent.VK_DOWN, KeyEvent.VK_SPACE };
		for (int i = 0; i < keys.length; i++) {
			if (e.getKeyCode() == keys[i]) {
				this.controls[i] = e.getID() == KeyEvent.KEY_PRESSED;
			}
		}
		if (e.getKeyCode() == KeyEvent.VK_ESCAPE && !this.isApplet) {
			System.exit(0);
		}
	}

	public void buildFrame() {
		Frame f = new Frame("Tile Based Maps Tutorial");
		f.addWindowListener(new WindowAdapter() {
			public void windowClosing(WindowEvent e) {
				System.exit(0);
			}
		});
		f.setSize(640, 480);
		f.setResizable(false);
		Dimension dimension = getToolkit().getScreenSize();
		Rectangle rectangle = f.getBounds();
		f.setLocation((dimension.width - rectangle.width) / 2,
				(dimension.height - rectangle.height) / 2);
		f.add(this);
		f.setVisible(true);
		this.isApplet = false;
		this.init();
		this.start();
	}

	public static void main(String[] args) {
		TileMap1 g = new TileMap1();
		g.buildFrame();
	}

	class Sprite {
		int x;
		int y;

		int dx;
		int dy;

		Sprite(int px, int py) {
			x = px * 32 + 6;
			y = py * 32 + 6;
		}

		void move(int pDx, int pDy) {
			dx = pDx;
			dy = pDy;

			if (pDy != 0) {
				if (canMove(x, y + dy)) {
					checkDoor((int) Math.floor(y / 32),
							(int) Math.floor(x / 32));
					y += dy;
				}
			}

			if (pDx != 0) {
				if (canMove(x + dx, y)) {
					checkDoor((int) Math.floor(y / 32),
							(int) Math.floor(x / 32));
					x += dx;
				}
			}
		}

		boolean canMove(int x, int y) {
			int downY = (int) Math.floor((y + 20) / 32);
			int upY = (int) Math.floor(y / 32);
			int leftX = (int) Math.floor(x / 32);
			int rightX = (int) Math.floor((x + 20) / 32);

			if (dy == -1) {
				return (!isSolid(upY, leftX) && !isSolid(upY, rightX));
			} else if (dy == 1) {
				return (!isSolid(downY, leftX) && !isSolid(downY, rightX));
			}

			if (dx == -1) {
				return (!isSolid(downY, leftX) && !isSolid(upY, leftX));
			} else if (dx == 1) {
				return (!isSolid(upY, rightX) && !isSolid(downY, rightX));
			}

			return false;
		}

		private boolean isSolid(int j, int i) {
			return (currentMap[j][i] == 1);
		}

		void render(Graphics g) {
			// Body
			g.setColor(Color.YELLOW);
			g.fillOval(x, y, 20, 20);
			g.setColor(Color.BLACK);
			g.drawOval(x, y, 20, 20);

			// Eyes
			g.setColor(Color.WHITE);
			g.fillOval(x + 2, y + 5, 8, 10);
			g.fillOval(x + 10, y + 5, 8, 10);
			g.setColor(Color.BLACK);
			g.drawOval(x + 2, y + 5, 8, 10);
			g.drawOval(x + 10, y + 5, 8, 10);
			g.fillOval(x + 4 + (dx * 2), y + 8 + (dy * 2), 4, 4);
			g.fillOval(x + 12 + (dx * 2), y + 8 + (dy * 2), 4, 4);
		}
	}
}