多线程是Java平台的一个重要特性。要了解多线程首先就要了解进程与线程的区别,进程是程序在处理机中的一次运行,一个进程既包括其所要执行的指令,也包括了执行指令所需的系统资源,不同进程所占用的系统资源相对独立,所以进程是重量级的任务,它们之间的通信和转换都需要操作系统付出较大的开销。而线程是进程中的一个实体,是被系统独立调度和分派的基本单位。线程自己基本上不拥有系统资源,但它可以与同属一个进程的其他线程共享进程所拥有的全部资源。所以线程是轻量级的任务,它们之间的通信和转换只需要较小的系统开销。Java支持多线程编程,因此用Java编写的应用程序可以同时执行多个任务。Java的多线程机制使用起来非常方便,用户只需关注程序细节的实现,而不用担心后台的多任务系统。
Java语言里,线程表现为线程类。Thread线程类封装了所有需要的线程操作控制。在设计程序时,必须很清晰地区分开线程对象和运行线程,可以将线程对象看作是运行线程的控制面板。在线程对象里有很多方法来控制一个线程是否运行,睡眠,挂起或停止。线程类是控制线程行为的唯一的手段。一旦一个Java程序启动后,就已经有一个线程在运行。可通过调用Thread.currentThread方法来查看当前运行的是哪一个线程。
实现线程一般有两种手段,一种是继续Thread类,另外一种是实现Runable接口,就继承Thread类而言,大致框架为:
class 类名 extends Thread{
方法1;
方法2;
....
//重写run方法
public void run(){
....
}
.....
}
线程的状态表示线程正在进行的活动以及在此时间段内所能完成的任务.线程有创建,可运行,运行中,阻塞,死亡五中状态.一个具有生命的线程,总是处于这五种状态之一:
1.创建状态
使用new运算符创建一个线程后,该线程仅仅是一个空对象,系统没有分配资源,称该线程处于创建状态(new thread)
2.可运行状态
使用start()方法启动一个线程后,系统为该线程分配了除CPU外的所需资源,使该线程处于可运行状态(Runnable)
3.运行中状态
Java运行系统通过调度选中一个Runnable的线程,使其占有CPU并转为运行中状态(Running).此时,系统真正执行线程的run()方法.
4.阻塞状态
一个正在运行的线程因某种原因不能继续运行时,进入阻塞状态(Blocked)
5.死亡状态
线程结束后是死亡状态(Dead)
创建线程和启动线程并不相同,在一个线程对新线程的Thread对象调用start()方法之前,这个新线程并没有真正开始执行。Thread对象在其线程真正启动之前就已经存在了,而且其线程退出之后仍然存在。这可以让您控制或获取关于已创建的线程的信息,即使线程还没有启动或已经完成了。
另外,在启动线程时,我们只能调用 start()方法。
下面是一个小球碰撞的多线程游戏代码:
主界面的类:
package com.csu.lq0715;
import java.awt.BorderLayout;
import java.awt.Dimension;
import java.awt.FlowLayout;
import java.awt.Graphics;
import java.awt.Panel;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
public class MoveBall extends JFrame{
private JPanel mainPal;
//创建数组队列,用于存储线程
ArrayList<myBall> list = new ArrayList<myBall>();
public static void main(String[] args) {
// //实例化MoveBall 类对象
// MoveBall mb = new MoveBall();
// //调用方法
// mb.initUI();
new MoveBall().initUI();
}
//初始化窗口
public void initUI() {
//初始化窗体界面
this.setSize(new Dimension(600,600));//设置窗口大小
this.setTitle("线程--小球运动"); //设置窗口标题
this.setLocationRelativeTo(null); //设置窗口显示位置
this.setDefaultCloseOperation(3); //关闭窗口、结束程序
JPanel toolPal = new JPanel(new FlowLayout());
this.add(toolPal,BorderLayout.NORTH);
//为窗口添加按钮
JButton jbu1 = new JButton(" ADD ");
jbu1.addActionListener(al);
toolPal.add(jbu1);
JButton jbu2 = new JButton("PAUSE");
toolPal.add(jbu2);
jbu2.addActionListener(al);
JButton jbu3 = new JButton("START");
toolPal.add(jbu3);
jbu3.addActionListener(al);
JButton jbu4 = new JButton(" END ");
jbu4.addActionListener(al);
toolPal.add(jbu4);
mainPal = new JPanel();
this.add(mainPal, BorderLayout.CENTER);
this.setVisible(true); //窗口可见
//设置变量,控制背景移动
int x = 0, y = 0;
//根据指定文件创建ImageIcon
ImageIcon bkIcon = new ImageIcon("image/backg.png");
while(true){
try {
myBall.sleep(10);
} catch (InterruptedException e) {
e.printStackTrace();
}
//创建缓冲图片
BufferedImage bfImg = new BufferedImage(mainPal.getWidth(),
mainPal.getHeight(),BufferedImage.TYPE_INT_RGB);
//传递画布
Graphics g = bfImg.getGraphics();
//设置背景颜色
g.setColor(mainPal.getBackground());
g.fillRect(0, 0, mainPal.getWidth(), mainPal.getHeight());
//添加背景图片
g.drawImage(bkIcon.getImage(), x, y, null);
x-=5; //背景向左移动
//第二张背景图片
g.drawImage(bkIcon.getImage(), x+bkIcon.getIconWidth(),
y, null);
if(x+bkIcon.getIconWidth()<=0){
x=0;
}
//将小球置于背景画布上
for(int i=0;i<list.size();i++){
myBall mbl = list.get(i);
mbl.draw(g);
}
mainPal.getGraphics().drawImage(bfImg, 0, 0, null);
}
}
//创建事件处理类,实现按钮事件
private ActionListener al = new ActionListener(){
public void actionPerformed(ActionEvent e) {
//获取按钮上的动作命令
String acd = e.getActionCommand();
switch(acd){
case " ADD ":
//实例化线程对象
myBall mbl = new myBall(mainPal, list);
//启动线程,只能调用start方法
mbl.start();
//将线程添加到数组队列中
list.add(mbl);
break;
case "PAUSE":
//遍历数组队列,查看线程标志位pFlag
for(int i=0;i<list.size();i++){
myBall p = list.get(i);
p.setPFlag(true);
}
break;
case "START":
//遍历数组队列,查看线程标志位pFlag
for(int i=0;i<list.size();i++){
myBall p = list.get(i);
p.setPFlag(false);
}
break;
case " END ":
//遍历数组队列,查看线程标志位sFlag
for(int i=0;i<list.size();i++){
// myBall s = list.get(i);
// s.setPFlag(false);
// s.setSFlag(true);
list.remove(i);
}
break;
}
}
};
}
小球类:
package com.csu.lq0715;
import java.awt.Color;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.util.ArrayList;
import java.util.Random;
import javax.swing.JFrame;
import javax.swing.JPanel;
//线程类myBall继承Thread
public class myBall extends Thread {
private JPanel mainPal;
private Graphics g; //传递画布、画笔
Random rand = new Random(); //创建随机变量
private int x ,y ; //定义小球坐标
private int radius; //定义小球半径
private int dx ,dy;//创建变量,小球移动增量
private int rad ,blue ,green; //颜色变量
private boolean pFlag = false, sFlag = false; //暂停、结束暂停标志位
private ArrayList<myBall> list; //储存小球的数组队列
public void setPFlag(boolean pFlag){
this.pFlag = pFlag;
}
public void setSFlag(boolean sFlag){
this.sFlag = sFlag;
}
//创建方法,获取画布、画笔
public myBall(JPanel mainPal, ArrayList list){
this.mainPal = mainPal;
this.g = mainPal.getGraphics();
this.list = list;
radius = rand.nextInt(20)+20; //改变半径
x = rand.nextInt(380)+20; //改变坐标
y = rand.nextInt(380)+20;
dx = rand.nextInt(4)+1; //增量改变
dy = rand.nextInt(4)+1;
rad = rand.nextInt(155); //三原色值改变
blue = rand.nextInt(155);
green = rand.nextInt(155);
}
//重写父类run方法
public void run(){
while(true){
try {
Thread.sleep(20);
} catch (InterruptedException e) {
e.printStackTrace();
}
Graphics2D g2d = (Graphics2D) g;
//设置图形去除锯齿状
g2d.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
RenderingHints.VALUE_ANTIALIAS_ON);
//暂停标志位判断
if(pFlag){
continue; //跳出循环
}
//clear(); //清除小球方法
//结束暂停标志位判断
if(sFlag){
return; //跳出方法
}
move(); //小球移动方法
//draw(g); //绘制小球方法
}
}
public void draw(Graphics g) {
g.setColor(new Color(rad,blue,green));
g.fillOval(x-radius, y-radius, 2*radius, 2*radius);
int rdu = radius;
int x0 = x;
for(int i=0;i<4;i++){
Color clr = g.getColor();
g.setColor(new Color(clr.getRed()+25,
clr.getBlue()+25,clr.getGreen()+25));
g.fillOval(x0-rdu, y-rdu, 2*rdu, 2*rdu);
x0--;
rdu--;
}
}
public void move() {
x+=dx;
y+=dy;
//禁止小球出界
if(x<=radius){
dx = -dx;
}
if(x>=mainPal.getWidth()-radius){
dx = -dx;
}
if(y<=radius){
dy = -dy;
}
if(y>=mainPal.getHeight()-radius){
dy = -dy;
}
//碰撞处理,比较圆心之间距离,遍历数组队列,找出当前球与其他球的圆心距离
for(int i=0;i<list.size();i++){
myBall ball = list.get(i);
if(this == ball){
continue;
}
int xx = Math.abs(this.x - ball.x);
int yy = Math.abs(this.y - ball.y);
int xy = (int) Math.sqrt(xx*xx + yy*yy);
if(xy<=this.radius+ball.radius+2){
this.dx = -this.dx;
this.dy = -this.dy;
ball.dx = -ball.dx;
ball.dy = -ball.dy;
}
}
}
public void clear() {
//清除小球
g.setColor(mainPal.getBackground());
g.fillOval(x-radius-1, y-radius-1, 2*radius+2, 2*radius+2);
}
}