多线程概念
进程:当点开英雄联盟的时候,我们就启动了一个进程。如果这时候又打开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接口的。