编写多线程程序,太阳和其他每个行星分别对应一个线程。给定一个数d,要求每个行星都以其实际速度d倍的速度行进。假设太阳是不动的。所以其他行星的速度应当取相对于太阳的速度。每个行星于太阳的距离应当取实际距离的一个比例值。具体的比例值取值只要能使太阳系行星运行图比较直观或者美观就可以。
假设中心(0,0),x=r*cosθ,y=r*sinθ,用角速度计算更新位置。
下面用匀速圆周运动模拟行星运行。八大行星:水星,金星,地球,火星,木星,土星,天王星,海王星。
每个行星对应一个线程,计算行星当前角度;太阳系绘制线程一个,负责场景绘制。共9个线程并发执行。
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Image;
import javax.swing.ImageIcon;
import javax.swing.JFrame;
import javax.swing.JPanel;
//行星动画主窗口
public class PlanetAnimation extends JFrame{
Data sharedData = new Data(); //构造数据对象,里面有行星数据,该对象传递给各个线程
ExclusiveData planetAngle=new ExclusiveData();//各个星球当前的角度
DrawPanel drawPanel;//绘制面板
starThread planetThread[]=new starThread[8];//每个行星一个线程,负责位置更新工作
DrawThread drawThread;//负责太阳系全部绘制工作的线程
int i,j;
public PlanetAnimation() {
super("太阳系行星运行图");
//下面布局界面
//构造绘制面板
drawPanel=new DrawPanel(sharedData,planetAngle);
Container c = getContentPane();
c.add(drawPanel,BorderLayout.CENTER);//画布放在中间
//加载宇宙背景
sharedData.backgraundImg=new ImageIcon("panel.jpg").getImage();
//下面构造8个行星的线程,并启动线程。每个线程计算行星的当前角度
for(i=0;i<8;i++)
{
planetThread[i]=new starThread(sharedData,planetAngle,i);//每个行星的线程
planetThread[i].start();//启动行星线程
}
drawThread=new DrawThread(drawPanel);//创建太阳系绘制线程
drawThread.start();//启动太阳系绘制线程
}
public static void main(String[] args) {
// TODO Auto-generated method stub
PlanetAnimation exp = new PlanetAnimation();//行星动画主窗口
exp.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
exp.setSize(exp.getMaximumSize());//最大化窗口
exp.setVisible(true);
}
}
//画布、该类负责场景绘制
class DrawPanel extends JPanel
{
int i,j,x,y;
int width,height;
Data shareddata; //行星数据
ExclusiveData angledata;//行星的当前角度
DrawPanel(Data data1,ExclusiveData data2)//传入行星数据及行星当前角度
{
shareddata=data1;
angledata=data2;
}
//绘制太阳系场景
void draw()
{
shareddata.x0=this.getWidth()/2; //计算中心点(太阳)
shareddata.y0=this.getHeight()/2;
repaint(); //Java虚拟机内部调用paintComponent()方法实现绘制当前面板
}
//真正绘制场景
protected void paintComponent(Graphics g)//重写父类方法
{
//清空并绘制背景
g.clearRect(0, 0, getWidth(), getHeight());//清空画布
g.drawImage(shareddata.backgraundImg, 0, 0, this.getWidth(), this.getHeight(), this);
//绘制宇宙背景
//画太阳
width=(int)shareddata.planeSize[8];//获取太阳直径
height=(int)shareddata.planeSize[8];
g.setColor(shareddata.color[8]);//取绘制太阳的颜色
g.fillOval(shareddata.x0-width/2,shareddata.y0-height/2, width, height);//画太阳
//画各个行星的轨道
for(i=0;i<8;i++)//画8个行星轨道
{
g.setColor(shareddata.color[i]);//取轨道颜色
width=(int)(2*shareddata.radius[i]);//圆的宽高
height=(int)(2*shareddata.radius[i]);
//下面绘制轨道圆
g.drawOval(shareddata.x0-shareddata.radius[i], shareddata.y0-shareddata.radius[i], width, height);
}
//画八个行星
for(i=0;i<8;i++)
{
//该行星i当前位置(x,y)计算
int r = shareddata.radius[i]; //取当前行星距离太阳中心的距离
//下面计算行星当前坐标;当前坐标=太阳中心坐标+行星当前角度对应坐标偏移
//计算该行星中心的当前x坐标
x=shareddata.x0+(int)(r*Math.cos(angledata.angle[i]*Math.PI/180));
//计算该行星中心的当前y坐标
y=shareddata.y0+(int)(r*Math.sin(angledata.angle[i]*Math.PI/180));
g.setColor(shareddata.color[i]); //取行星绘制颜色
width=(int)shareddata.planeSize[i];//取行星直径
height=width;
g.fillOval(x-width/2, y-height/2, width, height);//绘制行星i
g.drawString(shareddata.name[i], x+width/2,y);//绘制行星的名字
}
}
}
//八大行星的线程类
class starThread extends Thread
{
int id;
//行星编号:水星0,金星1,地球2,火星3,木星4,土星5,天王星6、海王星7
Data dataShared; //共享数据
ExclusiveData angleData;//行星当前角度
long lastTime,now;//上次时刻,当前时刻
public starThread(Data data1,ExclusiveData data2,int i)
{
id=i; //八大行星各自的编号
dataShared=data1; //传入共享数据
angleData=data2; //传入行星当前角度
}
//八大行星的线程体,负责计算每个行星的当前角度(用角度表示)
public void run()//更新线程
{
lastTime=System.currentTimeMillis();//取当前时刻
while(true)//行星角度循环更新
{
now=System.currentTimeMillis();//返回当前的毫秒数
//下面计算当前行星id的当前角度:新的角度=原角度+(该行星角速度*上次到现在经历的时间长度)*速度影响因子
angleData.angle[id]=(angleData.angle[id]+dataShared.angleSpeed[id]*((now-lastTime)/100)*dataShared.d)%360;
lastTime=now;//保留当前时刻
try {
Thread.sleep(200);//每200毫秒更新行星角度
}catch(InterruptedException e)
{
System.err.println("异常");
}
}//end of while
}
}
//太阳系绘制线程
class DrawThread extends Thread
{
DrawPanel drawPanel;//画布
DrawThread(DrawPanel Panel)
{
drawPanel=Panel; //保存绘制面板
}
//太阳系线程体:每隔100毫秒完成一次绘制
public void run()
{
while(true)
{
drawPanel.draw();//绘制太阳系场景
try {
Thread.sleep(100);//每100毫秒更新行星角度
}catch(InterruptedException e)
{
System.err.println("异常");
}
}
}
}
//类对象包含有关行星的数据
class Data
{
Image backgraundImg; //背景图像
float d=5; //速度影响因子,模型以实际速度的d倍来行走
int x0,y0;//太阳中心
float radiusBase = 210; //用于调节绘制效果的半径调节因子
float sizeBase=5; //行星直径调节因子
float speedBase =1; //角速度调节因子
行星的公转周期(天):(与最快的水星比较的倍数)
//水星: 88(1) 金星: 225 (2.5)地球: 365 (4.1);火星: 687 (7.8)
//木星: 4333 (49) 土星10760: (122) 天王星:30799 (350) 海 王星: 60118 (683)
//下面计算:每个行星的角速度=每天转动的角度*角速度调节因子=(360 度/公转周期天数)*角速度调节因子
float[] angleSpeed= {360/88f*speedBase,360/225f*speedBase,360/365f*speedBase,360/687f*speedBase,360/4333f*speedBase,360/10760f*speedBase,360/30799f*speedBase,360/60118f*speedBase};
//顺序0~7:水星,金星,地球,火星,木星,土星,天王星,海王星
//各个行星的实际直径:(与最小的木星相比的倍数)
//水星: 49.532千公里(10) 金星: 12.104千公里(2.5)
//地球:12.756千公里(3) 火星: 6.796千公里(1.4)
//木星: 4.88千公里(1) 土星: 120.536千公里(25) 天
//王星: 51.8千公里(10) 海王星: 49.532千公里(10)
太阳: 1392千公里(284)
//下面计算每个行星的直径:行星直径=(行星直径/最小木星的直径)*行星 直径调节因子
double planeSize[]= {49.5/4.9*sizeBase,12.1/4.9*sizeBase,12.7/4.9*sizeBase,6.7/4.9*sizeBase,4.9/4.9*sizeBase,120.5/4.9*sizeBase,51.8/4.9*sizeBase,49.5/4.9*sizeBase,220/4.9*sizeBase};
//顺序0~8:水星,金星,地球,火星,木星,土星,天王星、海王星,太阳
//各个行星的公转半径(亿公里): (与最近的水星比的倍数)
//水星:0.5791 (1) 金星: 1.082 (2) 地球: 1.496 (3) 火星: 2.2794 (4)
木星: 7.7833 (13) 土星: 14.294 (24.5) 天王星: 28.7668(50) 海王星: 45.04 (77.5)
//下面计算每个行星距离太阳中心的半径:行星的绘制半径=行星半径*半径调节因子
int radius[]= {(int)(0.57*radiusBase),(int)(1.08*radiusBase),(int)(1.2*radiusBase),(int)(1.5*radiusBase),(int)(1.8*radiusBase),(int)(2.0*radiusBase),(int)(2.2*radiusBase),(int)(2.4*radiusBase)};
Color color []= {Color.magenta,Color.YELLOW, Color.blue, Color.red, Color.cyan, Color. pink, Color. BLACK, Color. white, Color.red};
String name []= {"水星","金星","地球","火星","木星","土星","天王星","海王星","太阳"};
//各个行星的最新角度
}
//各个行星的最新角度
class ExclusiveData{
//下面是每个行星当前角度。由startThread线程更新。
double angle[]= {0f,0f,0f,0f,0f,0f,0f,0f};
//顺序0~7:水星,金星,地球,火星,木星,土星,天王星、海王星
}