多线程初探:三种方式创建多线程详细示例
多線程即在同一時間,可以做多件事情。
創建多線程有3種方式,分別是繼承線程類,實現Runnable接口,匿名類
一:線程概念
首先要理解進程(Processor)和線程(Thread)的區別
- 進程:啟動一個LOL.exe就叫一個進程。 接著又啟動一個DOTA.exe,這叫兩個進程。
- 線程:線程是在進程內部同時做的事情,比如在LOL里,有很多事情要同時做,比如"蓋倫” 擊殺“提莫”,同時“賞金獵人”又在擊殺“盲僧”,這就是由多線程來實現的。
示例1: 在蓋倫殺掉提莫后,賞金獵人才開始殺盲僧
Hero.java
public class Hero {public String name;public float hp;public int damage;public void attackHero(Hero h) {try {//為了表示攻擊需要時間,每次攻擊暫停1000毫秒Thread.sleep(1000);} catch (InterruptedException e) {// TODO Auto-generated catch block 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;} }?
TestThread.java
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 = 455;leesin.damage = 80;//蓋倫攻擊提莫while(!teemo.isDead()){gareen.attackHero(teemo);}//賞金獵人攻擊盲僧while(!leesin.isDead()){bh.attackHero(leesin);}} }?
打印日志:
蓋倫 正在攻擊 提莫, 提莫的血變成了 250 蓋倫 正在攻擊 提莫, 提莫的血變成了 200 蓋倫 正在攻擊 提莫, 提莫的血變成了 150 蓋倫 正在攻擊 提莫, 提莫的血變成了 100 蓋倫 正在攻擊 提莫, 提莫的血變成了 50 蓋倫 正在攻擊 提莫, 提莫的血變成了 0 提莫死了! 賞金獵人 正在攻擊 盲僧, 盲僧的血變成了 390 賞金獵人 正在攻擊 盲僧, 盲僧的血變成了 325 賞金獵人 正在攻擊 盲僧, 盲僧的血變成了 260 賞金獵人 正在攻擊 盲僧, 盲僧的血變成了 195 賞金獵人 正在攻擊 盲僧, 盲僧的血變成了 130 賞金獵人 正在攻擊 盲僧, 盲僧的血變成了 65 賞金獵人 正在攻擊 盲僧, 盲僧的血變成了 0 盲僧死了!二:多線程-繼承Thread
多線程:繼承線程類
使用多線程,就可以做到蓋倫在攻擊提莫的同時,賞金獵人也在攻擊盲僧
設計一個類KillThread,繼承Thread,并且重寫run方法
啟動線程辦法:
實例化一個KillThread對象,并且調用其start方法 就可以觀察到 賞金獵人攻擊盲僧的同時,蓋倫也在攻擊提莫
KillThread.java
public class KillThread extends Thread{private Hero h1;private Hero h2;public KillThread(Hero h1, Hero h2){this.h1 = h1;this.h2 = h2;}public void run(){while(!h2.isDead()){h1.attackHero(h2);}} }?
TestKillThread.java
public class TestKillThread {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();KillThread killThread2 = new KillThread(bh,leesin);killThread2.start();}}?
打印日志:
蓋倫 正在攻擊 提莫, 提莫的血變成了 250 賞金獵人 正在攻擊 盲僧, 盲僧的血變成了 390 賞金獵人 正在攻擊 盲僧, 盲僧的血變成了 325 蓋倫 正在攻擊 提莫, 提莫的血變成了 200 賞金獵人 正在攻擊 盲僧, 盲僧的血變成了 260 蓋倫 正在攻擊 提莫, 提莫的血變成了 150 賞金獵人 正在攻擊 盲僧, 盲僧的血變成了 195 蓋倫 正在攻擊 提莫, 提莫的血變成了 100 賞金獵人 正在攻擊 盲僧, 盲僧的血變成了 130 蓋倫 正在攻擊 提莫, 提莫的血變成了 50 賞金獵人 正在攻擊 盲僧, 盲僧的血變成了 65 蓋倫 正在攻擊 提莫, 提莫的血變成了 0 提莫死了! 賞金獵人 正在攻擊 盲僧, 盲僧的血變成了 0 盲僧死了!三:多線程-實現Runable()接口
創建類Battle,實現Runnable接口 啟動的時候,首先創建一個Battle對象,然后再根據該battle對象創建一個線程對象,并啟動
Battle battle1 = new Battle(gareen,teemo); new Thread(battle1).start();?
battle1 對象實現了Runnable接口,所以有run方法,但是直接調用run方法,并不會啟動一個新的線程。 必須,借助一個線程對象的start()方法,才會啟動一個新的線程。 所以,在創建Thread對象的時候,把battle1作為構造方法的參數傳遞進去,這個線程啟動的時候,就會去執行battle1.run()方法了。
Battle.java
public class Battle implements Runnable{private Hero h1;private Hero h2;public Battle(Hero h1, Hero h2){this.h1 = h1;this.h2 = h2;}public void run(){while(!h2.isDead()){h1.attackHero(h2);}} }?
TestRunableThread.java
public class TestRunableThread {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;Battle battle1 = new Battle(gareen,teemo);new Thread(battle1).start();Battle battle2 = new Battle(bh,leesin);new Thread(battle2).start();}}?
打印日志:
蓋倫 正在攻擊 提莫, 提莫的血變成了 250 賞金獵人 正在攻擊 盲僧, 盲僧的血變成了 390 蓋倫 正在攻擊 提莫, 提莫的血變成了 200 賞金獵人 正在攻擊 盲僧, 盲僧的血變成了 325 蓋倫 正在攻擊 提莫, 提莫的血變成了 150 賞金獵人 正在攻擊 盲僧, 盲僧的血變成了 260 蓋倫 正在攻擊 提莫, 提莫的血變成了 100 賞金獵人 正在攻擊 盲僧, 盲僧的血變成了 195 蓋倫 正在攻擊 提莫, 提莫的血變成了 50 賞金獵人 正在攻擊 盲僧, 盲僧的血變成了 130 蓋倫 正在攻擊 提莫, 提莫的血變成了 0 提莫死了! 賞金獵人 正在攻擊 盲僧, 盲僧的血變成了 65 賞金獵人 正在攻擊 盲僧, 盲僧的血變成了 0 盲僧死了!四:多線程-匿名類
使用匿名類,繼承Thread,重寫run方法,直接在run方法中寫業務代碼
匿名類的一個好處是可以很方便的訪問外部的局部變量。
前提是外部的局部變量需要被聲明為final。(JDK7以后就不需要了)
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 = 455;leesin.damage = 80;//匿名類Thread t1= new Thread(){public void 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();}}?
總結:
實現多線程的3種方式:
注: 啟動線程是start()方法,run()并不能啟動一個新的線程
實現Runnable接口比繼承Thread類所具有的優勢:
- 1):適合多個相同的程序代碼的線程去處理同一個資源
- 2):可以避免java中的單繼承的限制
- 3):增加程序的健壯性,代碼可以被多個線程共享,代碼和數據獨立
- 4):線程池只能放入實現Runable或callable類線程,不能直接放入繼承Thread的類
知識點
main方法其實也是一個線程。
在java中所以的線程都是同時啟動的,至于什么時候,哪個先執行,完全看誰先得到CPU的資源。
在java中,每次程序運行至少啟動2個線程。一個是main線程,一個是垃圾收集線程。因為每當使用java命令執行一個類的時候,實際上都會啟動一個JVM,每一個jVM實習在就是在操作系統中啟動了一個進程。
?
?
公眾號:一只阿木木
轉載于:https://www.cnblogs.com/yizhiamumu/p/9401727.html
總結
以上是生活随笔為你收集整理的多线程初探:三种方式创建多线程详细示例的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 分享.Net 设计模式大全
- 下一篇: Python做web开发,推荐几个能立马