[TOC]
# 常見方法
| 關鍵字 | 簡介 |
|---|---|
| sleep | 當前線程暫停 |
| join| 加入到當前線程中|
| setPriority| 線程優先級|
| yield| 臨時暫停|
| setDaemon | 守護線程 |
# 當前線程暫停
Thread.sleep(1000); 表示當前線程暫停1000毫秒 ,其他線程不受影響
Thread.sleep(1000); 會拋出InterruptedException 中斷異常,因為當前線程sleep的時候,有可能被停止,這時就會拋出 InterruptedException
```
package multiplethread;
public class TestThread5 {
public static void main(String[] args) {
Thread t = new Thread(){
@Override
public void run(){
int seconds = 0;
while (true) {
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.printf("已經玩了LOL %d 秒%n", seconds++);
}
}
};
t.start();
}
}
```
# 加入到當前線程中
首先解釋一下主線程的概念
所有進程,至少會有一個線程即主線程,即main方法開始執行,就會有一個看不見的主線程存在。
在42行執行t.join,即表明在主線程中加入該線程。
主線程會等待該線程結束完畢, 才會往下運行。
```
package multiplethread;
import charactor.Hero;
public class TestThread6 {
public static void main(String[] args) {
Hero garen = new Hero();
garen.name = "蓋倫";
garen.hp = 616;
garen.damage = 50;
Hero temmo = new Hero();
temmo.name = "提莫";
temmo.hp = 300;
temmo.damage = 30;
Hero bh = new Hero();
bh.name = "賞金獵人";
bh.hp = 500;
bh.damage = 65;
Hero lessin = new Hero();
lessin.name = "盲僧";
lessin.hp = 455;
lessin.damage = 80;
Thread t1 = new Thread() {
@Override
public void run() {
while (!temmo.isDead()) {
garen.attackHero(temmo);
}
}
};
t1.start();
//代碼執行到這里,一直是main線程在運行
try {
//t1線程加入到main線程中來,只有t1線程運行結束,才會繼續往下走
t1.join();
} catch (Exception e) {
e.printStackTrace();
}
Thread t2 = new Thread() {
@Override
public void run() {
while (!lessin.isDead()) {
bh.attackHero(lessin);
}
}
};
//會觀察到蓋倫把提莫殺掉后,才運行t2線程
t2.start();
}
}
```
# 線程優先級
當線程處于競爭關系的時候,優先級高的線程會有更大的幾率獲得CPU資源
為了演示該效果,要把暫停時間去掉,多條線程各自會盡力去占有CPU資源
同時把英雄的血量增加100倍,攻擊減低到1,才有足夠的時間觀察到優先級的演示
如圖可見,線程1的優先級是MAX_PRIORITY,所以它爭取到了更多的CPU資源執行代碼
Hero:
```
package charactor;
public class Hero {
public String name;
public float hp;
public int damage;
public void attackHero(Hero h) {
//把暫停時間去掉,多條線程各自會盡力去占有CPU資源
//線程的優先級效果才可以看得出來
/*try {
// 為了表示攻擊需要時間,每次攻擊暫停1000毫秒
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;
}
}
```
TestThread4:
```
package multiplethread;
import charactor.Hero;
public class TestThread4 {
public static void main(String[] args) {
Hero garen = new Hero();
garen.name = "蓋倫";
garen.hp = 6160;
garen.damage = 1;
Hero teemo = new Hero();
teemo.name = "提莫";
teemo.hp = 3000;
teemo.damage = 1;
Hero bh = new Hero();
bh.name = "賞金獵人";
bh.hp = 5000;
bh.damage = 1;
Hero leesin = new Hero();
leesin.name = "盲僧";
leesin.hp = 5550;
leesin.damage = 1;
// 匿名類
Thread t1 = new Thread() {
public void run() {
while (!teemo.isDead()) {
garen.attackHero(teemo);
}
}
};
Thread t2 = new Thread() {
public void run() {
while (!leesin.isDead()) {
bh.attackHero(leesin);
}
}
};
t1.setPriority(Thread.MAX_PRIORITY);
t2.setPriority(Thread.MIN_PRIORITY);
t1.start();
t2.start();
}
}
```
# 臨時暫停
當前線程,臨時暫停,使得其他線程可以有更多的機會占用CPU資源
```
package multiplethread;
import charactor.Hero;
public class TestThread7 {
public static void main(String[] args) {
Hero garen = new Hero();
garen.name = "蓋倫";
garen.hp = 6160;
garen.damage = 1;
Hero temmo = new Hero();
temmo.name = "提莫";
temmo.hp = 3000;
temmo.damage = 1;
Hero bh = new Hero();
bh.name = "賞金獵人";
bh.hp = 5000;
bh.damage = 1;
Hero lessin = new Hero();
lessin.name = "盲僧";
lessin.hp = 4550;
lessin.damage = 1;
Thread t1 = new Thread() {
@Override
public void run() {
while (!temmo.isDead()) {
garen.attackHero(temmo);
}
}
};
Thread t2 = new Thread() {
@Override
public void run() {
while (!lessin.isDead()) {
Thread.yield();
bh.attackHero(lessin);
}
}
};
t1.setPriority(5);
t2.setPriority(5);
t1.start();
t2.start();
}
}
```
# 守護線程
守護線程的概念是: 當一個進程里,所有的線程都是守護線程的時候,結束當前進程。
就好像一個公司有銷售部,生產部這些和業務掛鉤的部門。
除此之外,還有后勤,行政等這些支持部門。
如果一家公司銷售部,生產部都解散了,那么只剩下后勤和行政,那么這家公司也可以解散了。
守護線程就相當于那些支持部門,如果一個進程只剩下守護線程,那么進程就會自動結束。
守護線程通常會被用來做日志,性能統計等工作。
```
package multiplethread;
public class TestThread5 {
public static void main(String[] args) {
Thread t = new Thread(){
@Override
public void run(){
int seconds = 0;
while (true) {
try {
Thread.sleep(1000);
} catch (Exception e) {
e.printStackTrace();
}
System.out.printf("已經玩了LOL %d 秒%n", seconds++);
}
}
};
t.setDaemon(true);
t.start();
}
}
```
# 練習-英雄充能
英雄有可以放一個技能叫做: 波動拳。
每隔一秒鐘,可以發一次,但是只能連續發3次。
發完3次之后,需要充能5秒鐘,充滿,再繼續發。
借助本章節學習到的知識點,實現這個效果
```
package charactor;
import java.io.Serializable;
public class Hero3 implements Serializable {
public String name;
public float hp;
public Hero3() {
}
public Hero3(String name) {
this.name = name;
}
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;
}
int totalTime = 3;
public void adugen() {
while (true) {
for (int i = 0; i < totalTime; i++) {
System.out.printf("波動拳第%d發%n", i + 1);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
System.out.println("開始為時5秒的充能");
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
public static void main(String[] args) {
Hero3 h = new Hero3();
h.name = "紅仔";
h.adugen();
}
}
```