线程是程序执行的最小单位。如果说QQ是一个进程的话,它就像一个容器,管理和分配着资源。QQ能同时做很多事情,比如接收消息,发送消息,在内置浏览器里冲浪。而同时进行这些事情就需要线程这个概念了。也就是说进程相当于资源分配平台,而线程则是资源调度的基本单位。
创建线程的两种方式
举个例子,把一个羽毛球馆想象成一个进程,里面都多个场地在同时进行比赛(线程)。
继承Thread类创建线程
于是我们先定义一个Player类,为其声明进攻方法和判断胜利方法。
public class Player {
private String name;
private int score=0;
private double attackRate; // 进攻成功率
private double defenseRate; // 防守成功率
public Player(String name){
this.name = name;
}
public void offense(Player p){
this.attackRate = Math.random();
this.defenseRate = Math.random();
p.attackRate = Math.random();
p.defenseRate = Math.random();
try {
Thread.sleep(500); // 模拟间歇,攻防后休息一下
} catch (InterruptedException e) {
e.printStackTrace();
}
if (this.attackRate > p.defenseRate){
this.score += 1;
System.out.format("%s 进攻 %s成功, %s的得分变为 %d%n",this.name,p.name,this.name,this.score);
}
if(this.isWin())
System.out.println(this.name +"取得胜利!");
}
public boolean isWin() {
return this.score >= 5;
}
}
再定义一个线程类OffenseThred继承Thread类,重写run方法,这个方法是线程执行的主体内容。这个类表示一个场地内进行的一场比赛(线程)。
public class OffenseThread extends Thread{
private Player p1;
private Player p2;
public OffenseThread(Player p1, Player p2){
this.p1 = p1;
this.p2 = p2;
}
@Override // 重写run方法
public void run(){
while (true){
if (p1.isWin() || p2.isWin()){break;}
else {
p1.offense(p2);
p2.offense(p1);
}
}
}
最后写一个测试类,测试一下多线程同时进行的效果。
public class BadmintonGame {
public static void main(String[] args) {
Player linDan = new Player("林丹");
Player liZongS = new Player("李宗盛");
Player zs = new Player("张三");
Player ls = new Player("李四");
// 通过创建线程对象
OffenseThread offenseThread1 = new OffenseThread(linDan, liZongS); // 职业组比赛线程
offenseThread1.start(); // 调用start()方法
OffenseThread offenseThread2 = new OffenseThread(zs, ls); // 业余组比赛线程
offenseThread2.start();
}
效果如下,可以看到两场比赛(线程)是同时进行的。
实现Runnable接口
创建一个OffenseRun类去实现Runnable接口并实现run方法:
public class OffenseRun implements Runnable{
private Player p1;
private Player p2;
public OffenseRun(Player p1, Player p2){
this.p1 = p1;
this.p2 = p2;
}
// 实现run方法
public void run(){
while (true){
if (p1.isWin() || p2.isWin()){break;}
else {
p1.offense(p2);
p2.offense(p1);
}
}
}
}
创建OffenseRun的对象,最后将对象作为参数传入Thread构造方法中,创建线程对象,调用start方法执行线程。
// 实现runable接口 将对象作为参数传入Thread构造方法中
OffenseRun offenseRun1 = new OffenseRun(linDan, liZongS);
new Thread(offenseRun1).start();
OffenseRun offenseRun2 = new OffenseRun(zs, ls);
new Thread(offenseRun2).start();
两种方法的比较
通过实现Runnable接口的方法比前者要更加灵活,因为前者继承了Thread类就不能继承其他类了。实现Runnable的方法可以更方便地实现多个线程共享数据的行为。
其实平常开发中,有关线程的具体操作都不要自己动手,基本都由各种优秀的框架封装实现了。自己只需要加上注解,设置一些线程上的参数即可。