多线程
在没有引入多线程概念之前,我们写的程序都是单线程的,相较于多线程的程序而言单线程程序较为简单,运行结果也是大致确定的(除开类似随机数这些特殊情况,相同条件下运行的结果是相同的)。多线程程序结构较为复杂,程序的运行结果也难以预测,但是多线程程序通过若干个线程的并发运行,极大地提升了作业的处理效率,充分地利用了计算机资源,并且多线程程序本身也更加符合大多数的应用场景。
下面通过一个多线程实例了解多线程程序的特性
假设一个场景,托尼和灭霸在战斗,与此同时小蜘蛛也在和神秘客掐架,如果使用单线程程序表达的话,我们就需要开启两个程序,在两个main方法中实现,因为main方法内的代码是顺序执行的,不能同时实现两个战斗场景。当我们引入两个线程,就能在一个程序中描述两场战斗。
public class Compaign {
public static void main(String[] args) {
Role IronMan = new Role("钢铁侠",50,500);
Role Thanos = new Role("灭霸",50,700);
Role SpiderMan = new Role("蜘蛛侠",25,300);
Role Mysterio = new Role("神秘客",20,200);
Battle infinitywar = new Battle(IronMan,Thanos);
Battle farfromhome = new Battle(SpiderMan,Mysterio);
//start()方法启动线程,start()方法启动一个线程,线程内部调用各自的run()方法,run()方法是一个普通的包含线程业务逻辑的方法,本身并不实现并发
new Thread(infinitywar).start();;
new Thread(farfromhome).start();
}
}
Battle类实现了Runnable接口,run方法表达了两个角色之间的战斗(为了简化逻辑,这里是单方面的拾掇)
public class Battle implements Runnable {
private Role r1;
private Role r2;
public Battle(Role r1,Role r2) {
this.r1 = r1;
this.r2 = r2;
}
@Override
public void run() {
//r1攻击r2
while(r2.isAlive()) {
r1.attack(r2);
}
}
}
Role类代码
public class Role {
private String name;
private int damage;
private int HP;
public Role(String name,int damage,int HP) {
this.name = name;
this.damage = damage;
this.HP = HP;
}
//被攻击减少血量
public void damaged(Role r) {
this.HP -= r.damage;
if(HP<=0) {
HP = 0;
System.out.println(this.name + "被击杀!");
}else {
System.out.println(this.name + "被" + r.name + "攻击,生命值剩余" + this.HP);
}
}
//攻击
public void attack(Role r) {
r.damaged(this);
}
//角色是否存活
public boolean isAlive() {
return HP>0?true:false;
}
}
运行结果:
可以看到,当我们调用start()方法开启两个线程以后,两个线程都开始运行,并且其运行的结果是不能确定的,尤其当多次运行这个程序后,会发现每一次的结果都不尽相同。
值得注意的是,在主函数中开启线程时调用start()方法开启一个新的线程,在线程内部,业务逻辑包含在run()方法中,通过JVM调用run()方法运行,run()方法本身并不实现线程的并发。
一个线程仅能被启动一次,当一个线程通过start()方法开启以后不能再次调用其start()方法。当其执行完成以后再次调用start()方法也是非法操作。具体参考官方API文档