多线程概念
进程:当点开英雄联盟的时候,我们就启动了一个进程。如果这时候又打开QQ音乐,那我们就是又开启了一个进程。
线程:线程是进程内部同时在做的事情,比如在英雄联盟游戏中,"盖伦正在击杀提莫",同一时刻"赏金猎人又在击杀盲僧",这个时候盖伦击杀提莫这件事就是一个线程,在这里两个线程在做事情,就统称多线程。
顺序执行线程
1、描述两件事情,并没有同时发生,只是一件事情发生完了以后,另一件事情才开始。Hero类
package com.thread;
public class Hero {
public String name;
public float hp;
public int damage;
public void attackHero(Hero h) {
try {
//为了表示攻击需要时间 每次攻击暂停1秒
Thread.sleep(1000);
}catch(InterruptedException e) {
e.printStackTrace();
}
h.hp -= damage;
System.out.format("%s 正在攻击 %s, %s的血变成了 %.0f%n", name, h.name, h.name, h.hp);
if(h.isDead()) {
System.out.println(h.name + "死了!");
}
}
//判断英雄死了没
public boolean isDead() {
return 0 >= hp?true:false; //血量大于0 没死 isDead=false
}
}
2、顺序执行两个模拟的线程,TestThread
package com.thread;
public class TestThread {
public static void main(String[] args) {
Hero gareen = new Hero();
gareen.name = "盖伦";
gareen.hp = 616;
gareen.damage = 50;
Hero teemo = new Hero();
teemo.name = "提莫";
teemo.hp = 300;
teemo.damage = 30;
Hero bh = new Hero();
bh.name = "赏金猎人";
bh.hp = 500;
bh.damage = 65;
Hero leesin = new Hero();
leesin.name = "盲僧";
leesin.hp = 445;
leesin.damage = 80;
//盖伦攻击提莫
while(!teemo.isDead()) { //提莫的是否死亡 false就是没死 !false=true 那么盖伦继续攻击 直到提莫没了
gareen.attackHero(teemo); //盖伦攻击提莫
}
//赏金猎人攻击盲僧
while(!leesin.isDead()) {
bh.attackHero(leesin); //赏金猎人攻击盲僧
}
}
}
效果

创建线程
三种方式:继承Thread类,实现Runnable接口,内部类

1、继承Thread类。Thread类实现了Runnable接口,这里run方法重写了Runnable中的run方法,重新定义算法,这个算法描述此线程在做什么事情。
package com.thread.thread1;
import com.thread.Hero;
//这里继承Thread Thread本质也是实现Runnable接口 THread重写run方法
public class KillThread extends Thread {
private Hero h1; //做两个英雄出来
private Hero h2;
public KillThread(Hero h1, Hero h2) { //把两个英雄放入killTHread中
this.h1 = h1;
this.h2 = h2;
}
public void run() { //这里继承 重新声明了run方法 没有用原本的
while(!h2.isDead()) {
h1.attackHero(h2);
}
}
}
启动线程测试,这里传入的对象作为参数,传递到线程类中的构造方法,实例出来的线程对象,调用其父类Thread的start方法,执行该线程的run函数。
package com.thread.thread1;
import com.thread.Hero;
public class TestT {
public static void main(String[] args) {
Hero gareen = new Hero();
gareen.name = "盖伦";
gareen.hp = 616;
gareen.damage = 50;
Hero teemo = new Hero();
teemo.name = "提莫";
teemo.hp = 300;
teemo.damage = 30;
Hero bh = new Hero();
bh.name = "赏金猎人";
bh.hp = 500;
bh.damage = 65;
Hero leesin = new Hero();
leesin.name = "盲僧";
leesin.hp = 455;
leesin.damage = 80;
//创建一个线程 里面盖伦和提莫在打架
KillThread killThread1 = new KillThread(gareen, teemo);
killThread1.start(); //启动线程 执行Thread中start方法 我们自己声明的线程类没有这个start方法
KillThread killThread2 = new KillThread(bh, leesin); //再创建一个线程
killThread2.start(); //第二个线程启动
//总结 两个线程互不影响
}
}
2、实现Runnable接口,实现接口,实现的是接口内的方式,override。
package com.thread.thread2;
import com.thread.Hero;
public class Battle implements Runnable{
private Hero h1;
private Hero h2;
public Battle(Hero h1, Hero h2) {
this.h1 = h1;
this.h2 = h2;
}
@Override
public void run() {
while(!h2.isDead()) {
h1.attackHero(h2);
}
}
}
编写测试类,重新new了一个线程,将自己实现的类的实例对象传入线程中,然后启动线程的start方法
package com.thread.thread2;
import com.thread.Hero;
public class TestT {
public static void main(String[] args) {
Hero gareen = new Hero();
gareen.name = "盖伦";
gareen.hp = 616;
gareen.damage = 50;
Hero teemo = new Hero();
teemo.name = "提莫";
teemo.hp = 300;
teemo.damage = 30;
Hero bh = new Hero();
bh.name = "赏金猎人";
bh.hp = 500;
bh.damage = 65;
Hero leesin = new Hero();
leesin.name = "盲僧";
leesin.hp = 455;
leesin.damage = 80;
//创建一个实现线程类的类的对象 但是这个对象没有start方法
Battle battle1 = new Battle(gareen, teemo);
new Thread(battle1).start(); //我们就将这个对象 传到Thread中 调用其中的start方法
Battle battle2 = new Battle(bh, leesin);
new Thread(battle2).start();
//两种创建线程的方法
//1、继承Thread方法 直接声明run方法 然后调用父类Thread的start启动线程
//2、实现Runnable接口 重写run方法 实例化该类,得到对象传入Thread构造方法中 调用其中的start方法 启动线程
}
}
3、编写内部类,类中创建线程,调用该线程对象的start方法。补充:内部类可以调用外部类的变量
package com.thread.thread3;
import com.thread.Hero;
public class TestT {
public static void main(String[] args) {
Hero gareen = new Hero();
gareen.name = "盖伦";
gareen.hp = 616;
gareen.damage = 50;
Hero teemo = new Hero();
teemo.name = "提莫";
teemo.hp = 300;
teemo.damage = 30;
Hero bh = new Hero();
bh.name = "赏金猎人";
bh.hp = 500;
bh.damage = 65;
Hero leesin = new Hero();
leesin.name = "盲僧";
leesin.hp = 455;
leesin.damage = 80;
//匿名类
Thread t1 = new Thread() { //匿名类 创建一个匿名对象
public void run() { //重新实现它的run方法
//匿名类中用到的外部的局部变量teemo 必须把teemo声明成final
//但是jdk7后 就不用加上final了
while(!teemo.isDead()) {
gareen.attackHero(teemo);
}
}
};
t1.start(); //调用该内部类的方法 启动线程对象
Thread t2 = new Thread() {
public void run() {
while(!leesin.isDead()) {
bh.attackHero(leesin);
}
}
};
t2.start(); //启动第二个线程
}
}
总结
线程的创建要么是创建本质都是实例Thread类,重写run方法(这个run方法是runnable接口中的),执行Thread类中的start方法启动线程。Thread类是实现Runnable接口的。