相对于Audio Player MIDlet应用程序,Bouncing Ball MIDlet应用程序相对复杂一点,它的主画面是运动的小球,而且有背景音乐,每个小球放在单独的线程里,背景音乐也是单开一个线程,所以说是一个相对复杂的多线程程序,很值得我们去学习。还是先来看程序,从程序中我们才能知晓作者的用心良苦,
BBall.java
public class BBall extends MIDlet implements CommandListener, Runnable {
先看它的事件处理
public void commandAction(Command c, Displayable s) {
if (c == exitCommand) {
synchronized(gameLock) {
if (game != null) {
game.destroy();
game = null;
}
}
destroyApp(false);
notifyDestroyed();
} else if ((s == theList && c == List.SELECT_COMMAND) || c == playCommand) {
idx = theList.getSelectedIndex();
new Thread(this).start();
}
}
注意最后一行代码是:new Thread(this).start();
BBall类实现了Runnable,下面是它的实现
public void run() {
System.out.println(Thread.currentThread().getName());
synchronized(gameLock) {
if (game == null) {
game = new BallCanvas(this);
}
display.setCurrent(game);
game.init(8, idx);
if (game.needAlert()) {
Alert alert = new Alert("Warning", "Cannot create player", null, null);
alert.setTimeout(1000);
display.setCurrent(alert, game);
}
game.start();
}
}
分析以上代码,不难得出以下几个结论:
1. 主程序GUI线程(我就叫它GUI线程),负责整个MIDlet程序的初始化显示;
而比较费CPU时间的game的创建和实例化,单独放在一个线程(我就叫它game线程)里
这一点是非常有必要的。
2. 这个类用了一个监视器对象gameLock来实现GUI线程和game线程之间的同步,这个同步的
必要性,开始我还怀疑过,后来加了以行代码后,才明白它存在的必要性
public void run() {
System.out.println(Thread.currentThread().getName());
synchronized(gameLock) {
if (game == null) {
game = new BallCanvas(this);
}
try{Thread.sleep(10000);}catch(InterruptedException ex){}
display.setCurrent(game);
game.init(8, idx);
if (game.needAlert()) {
Alert alert = new Alert("Warning", "Cannot create player", null, null);
alert.setTimeout(1000);
display.setCurrent(alert, game);
}
game.start();
}
}
然后生成,运行,单击no background,接着(当然是在十秒种以内了,)要是单击exit的话,你会发现程序并没有退出,原因很简单,game线程已经获得了gameLock的锁,GUI线程只能等待了。
考虑一下,如果此处不同步的话,因为我们不能预测cpu何时,以什么顺序来执行线程,一种情况,game线程在完成game的创建,即game= new BallCanvas(this);,cpu切换到GUI线程(可能这个人想突然退出,不想看效果了) ,执行下面语句
if (game != null) {
game.destroy();
game = null;
}
接着cpu又切换到了game线程,灾难发生了,game.init(8,idx);
所以说,在手机这种资源相对有限的设备上写程序,安全设计和性能设计非常重要!!