線程:
1.概念:線程就是一個獨立的運行單位,其內部數據和狀態都是完全獨立的。簡單的說,就是一旦觸發,就由它自己去運行,不用再管,由系統自行去根據代碼執行,所以一旦運行就馬上返回,不用等待。這樣可以實現多個線程同時執行。
2.實現線程的3種方式:
1.繼承Thread類實現線程
public class Bullet extends Thread{
// 運動的速度
private static int speed = 2;
// 傳入畫布
private Graphics g;
// 當前子彈的名字
String name;
// 傳入坦克的座標值
int x;
int y;
//調用啓動函數
public void run() {
shot();
}
public void shot{
"這裏寫入子彈運動的過程"
}
}
這裏實現了一個子彈的運行過程,只要在shot方法中畫出子彈運動的過程就可以了。這樣其實就實現了一個簡單的線程,當我們直接調用bullet的strat方法就可以了,如
Bullet bullet = new Bullet();
bullet.strat();
這裏調用的是strat方法,可是由於這是一個線程對象,所以系統自動調用run()方法的東西,並立即返回。
這裏問題就來了,我們爲什麼非要調strat去啓動run方法呢,爲什麼不直接調用shot方法呢?呵呵,其實可以去試一試的,因爲我們當時是設計有坦克的,這只是其中的子彈類而已,如果直接調用shot方法的話,需要等待,也就是說,在第一顆子彈結束之前,坦克是不能動的,並且不能發射第二顆子彈,明白了嗎。這就是線程的作用,可以並行。在子彈運行的同時,坦克也可以運行,這纔是符合邏輯。子彈作爲一個單獨的線程去運行。
注意:一定要記得重寫run()方法。
2.實現Runnable的方法實現線程
1.前面寫了很多來告訴爲什麼要使用線程,有什麼好處,並且也說了通過繼承的方法實現線程啓動,這裏介紹另一種常用方法,通過繼承Runnable的方法實現線程的啓動。還是以子彈作爲研究對象,如:
public class BulletRunnable implement Runnable {
//傳入的坦克對象
Tank tank;
//重寫構造方法
public BulletRunnable(Tank tank, Graphics g) {
this.g = g;
this.tank = tank;
}
//調用啓動函數
public void run() {
shot();
}
public void shot(){
"這裏畫出子彈運動的過程"
}
}
這裏創建了一個類,該類實現了Runnable接口,所以就必須實現它的抽象方法run(),其實前面的Thread也是實現的Runnable接口的,所以可以通過繼承Thread類來實現線程的啓動,現在我們自己寫了一個類實現了Runnable,所以也可以通過這個類來啓動線程。
所以只需要通過我們實現了接口的類創建一個線程,並調用線程即可。如:
BulletRunnable tr = new BulletRunnable(tank, g);
Thread thread = new Thread(tr);
// 線程啓動
thread.start();
這樣一樣可以啓動線程。
3.通過匿名內部類,實現接口Runnable
/**
* 啓動一個線程
*/
public void stratBullet(){
//通過匿名內部類實現接口
Runnable rab = new Runnable(){
public void run(){
“畫出子彈運行的過程”
}
}
//啓動線程
Thread thread = new Thread(rab);
thread.strat();
}
這樣也實現了一顆子彈的發射,由於篇幅緣故,沒有寫出具體畫出子彈的方法,因爲這是個很複雜的問題,要考慮的諸如碰到坦克和牆等等的情況,所以代碼非常複雜,沒有把具體情況寫出來。
3.sleep方法的運用。
1.其實sleep方法的運用是比較重要的,因爲一個線程在執行時,會一直佔用資源,這是不合理的,因爲一般情況下,比如一個坦克,在它未被消滅之前,會一直執行run方法,因此,在它在打死之前,其實一直都在調用run方法。如果不去處理這種情況,那麼系統的cpu佔用會達到100%,這是絕對不合理的,就像程序陷入死循環一樣的效果。所以我們需要調用Thread的sleep方法。它可以讓程序休眠一段時間,之後繼續運行。
2.寫出一段子彈類的,shot方法具體代碼;
while (true) {// 開始發射子彈
// 先畫一個子彈
g.drawImage(image, x, y, WideB, HighB, null);
try {
this.sleep(10);// 線程休眠
g.setColor(Color.BLACK);
g.fillRect(x, y, WideB, HighB);// 畫矩形把原先圖片蓋住
// 判斷坦克方向,改變相應運動座標
if (direction.equals("Right")) {
x += speed;
}
if (direction.equals("Left")) {
x -= speed;
}
if (direction.equals("Up")) {
y -= speed;
}
if (direction.equals("Down")) {
y += speed;
}
// 畫出新位置,走下一步
g.drawImage(image, x, y, WideB, HighB, null);
} catch (InterruptedException e) {
e.printStackTrace();
}
// 判斷是否到邊界,是跳出循環
if (x > 885 || x < -5|| y > 580|| y < -5) {
tank.countBomb++;
System.out.println(tank.countBomb);
break;
}
}
可以看出,其實在子彈出去邊界之前,一直是在以死循環的方式不斷執行,如果不讓程序休眠的話,就會非常快的執行完成,我們根本看不到子彈飛出的效果,也就是說子彈的運行速度是由子彈的休眠時間和速度一起影響的。只是子彈而已所以影響不太大,試想一下,如果一個坦克沒有休眠時間是多麼難看堪的事情,所以休眠,對於線程來說,是很重要的。
休眠時間以毫秒計算,如果參數是1000,則會休眠一秒。