【例9-1】不使用多线程和调用多线程的小球运动对比试验。
运行程序界面如图9-1所示。单击“不用多线程”按钮,小球开始作弹射运动。在小球运动1000次未完成之前,即使单击“停止”按钮,小球仍在运动。这说明一个不使用多线程的程序,在程序运行过程中不能加以控制。
然后单击“使用多线程”按钮,单击“停止”按钮,小球就停止,再单击“使用多线程”按钮,小球又开始运动。总之,调用多线程后,小球的运行能得到有效的控制。下面对本程序的设计给出几点说明。
图9-1 多线程对比试验
[编程说明]
(1)在上述程序中,bounce()和run()方法体的代码是完全相同的。调用方法bounce()时,单击“停止”按钮得到flag=false。但其while循环
仍在执行。
当调用方法run()时,同样的代码能使其while循环停止是因为run()属于多线程的方法,而多线程在其运行过程中是可以控制的。
(2)程序中一个值得注意之处是使用异或模式擦除旧的小球。在计算机动画中只有不断地擦除旧图,绘制新图才能使屏幕“动”起来。本例提供了异或模式作图在动画中的应用实例。
注意,JFrame默认的背景和前景色分别是浅灰色(lightgray)和红色(red)。所以程序画图用的当前色是红色(red),而canvas.getBackground()的结果是浅灰色(lightgray)。
在方法move()中,下面两条语句
的作用是当前色red与背景色作异或运算,即
称这个异或结果的颜色C为异或色。于是方法
用异或色C在颜色为lightgray的背景上画出的填充小球的颜色是
即画出的小球所显示的颜色是红色。
但若第1次调用move(),boolean first=true时,上面画出的红色小球通过下面的程序块
“擦除”第1次画出的小球。下面解析这个“擦除”的过程。注意,上面的语句(9.1.1)是在前面画出的红色小球的上再次用异或色C画小球,其结果颜色是
即在红色小球上用背景色画同样大小的小球,其实际作用是在画布上“擦除红色小球”。(www.xing528.com)
接下来程序代码块是小球运动的坐标算法代码。在坐标算法结束获得新的小球的坐标后,下面的语句
才是用异或色在背景上画小球的真正开始。这个红色小球经过延时10毫秒,在再次调用move()方法时,首先通过异或方法擦除,然后进入小球运动的坐标算法代码,依此类推。
(3)小球运动算法
小球运动程序需要计算小球在运动中的坐标并制作动画。这两部分,分别称其为小球运动的坐标算法。小球运动的坐标算法的依据是小球反弹满足入射角等于反射角的原理。具体算法如下:
1)获取画布canvas的尺寸d,d.width,d.height分别为画布的宽度和高度。
2)当小球到达和超出画布的左边界时,即当x<=0,设置小球在画布的左边界且水平运动方向取反,即
3)当小球到达和超出画布的右边界时,即当x+WIDTH>=d.width,设置小球在画布的右边界且水平运动方向取反,即
4)当小球到达和超出画布的上边界时,即当y<=0,设置小球在画布的上边界且垂直运动方向取反,即
5)当小球到达和超出画布的下边界时,即当y+HEIGHT>=d.height,设置小球在画布的下边界且垂直运动方向取反,即
可以简单地总结上述算法的过程是:
画小球→延时→擦除小球→移动坐标→再画小球→延时→再擦除小球……延时若干毫秒的作用是为了看清所画的图形。上面这个画图、擦除旧图,在新坐标处再画新图、再擦除的过程,加上延时的作用,只要移动的步长不要太大,在人的视觉中就会产生“连续移动”的动画的效果。这就是动画的基本原理。
在上面的例9-1中,已经初步接触了多线程。Java多线程的基础是3个方法:
通常,Java的程序应有一个线程——主线程。但是,可以在start()方法中启动另一个线程。这个线程要运行的代码在run()方法之中。这表明,在这个方法中的代码将在主线程执行其他代码时自动运行。在stop()方法中可以停止线程。
每一个线程都有一个优先级,在默认情况下线程的优先级为5,用常量NORM_PRIORITY表示。最高的优先级为10,即MAX_PRIORITY,最低的优先级为1,即MIN_PRIORITY。优先级高的线程先执行,优先级低的线程后执行。当线程中运行的代码创建一个新线程对象时,这个新线程拥有与创建它的线程一样的优先级。
线程可以设置为守护线程(daemonthread)。所谓守护线程就是为其他线程服务的线程。比如,下面的计时器线程被设置为守护线程:
其中语句
将计时器线程设置为守护线程。当程序中只有守护线程时,它就会停止,因为剩余的线程都是守护线程,再继续运行这个守护线程就没有意义了。当Java虚拟机启动时,通常至少有一个非daemon线程。Java虚拟机将持续地运行该线程直到发生下列情况之一:
●调用Runtime库的exit()方法,并且,安全管理器允许执行exit操作。
●所有的线程都不是守护线程并已终止。
●从调用的run()方法返回。
●在run()方法中抛出异常。
免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。