一、概述
為什么使用線程?從c開始,任何一門高級語言的默認執行順序是“按照編寫的代碼的順序執行”,日常開發過程中寫的業務邏輯,但凡不涉及並發的,都是讓一個任務順序執行以確保得到想要的結果。但是,當你的任務需要處理的業務比較多時,且這些業務前后之間沒有依賴(比如, a執行的過程中b也可以執行,b沒有必要必須等待a執行完畢再去執行),那么此時,我們可以將一個任務拆分成多個小任務。
例如,任務a負責接收鍵盤的輸入,b負責將一些參數及計算提前做好(假設計算量比較大),c負責將a的輸入和b的結果做和。此時,abc順序執行的話,如果a的輸入被阻塞了即正在等待用戶輸入,b就無法執行,而此時cpu處於空置狀態(假設是單cpu且單核),明顯效率不高。
換一個思路,假如:abc分開成為三個任務,a的輸入被阻塞了,那么此時就把b交給cpu去執行,待用戶輸入結果之后,b已經將計算結果輸出給了c,此時,用戶提交后,c便立即計算出了結果。
綜上:多線程解決的是並發的問題,目的是使任務執行效率更高,實現前提是“阻塞”。它們看上去時同時在執行的,但實際上只是分時間片試用cpu而已。
二、java中的多線程
1.定義任務
任務:簡單來說,就是一序列工作的集合,這些工作之間有前后順序,這一系列過程執行過后將實現一個結果或達到一個目的。
首先,思考一個問題,為什么要定義任務?作為java程序員,我們不關心底層的多線程機制是如何執行的,只關心我寫個怎樣的任務,java的底層的多線程機制才能認識,才能調用你的任務去執行。java是定義了Runnable接口讓你去實現,意思就是:你實現Runnable接口類定義一個類,該類的對象就是我能識別的任務,其他方式定義的程序,我都不會將它認為是任務。
好,到這里要明確一點,我們此時只談論任務,不說多線程。任務和你平時在一個類中編寫的代碼並無區別,只是按照java的要求實現了一個接口,並在該接口的run方法中編寫了你的代碼。也就是說,你平時想編寫一個類,該類能夠完成一些功能,這個類里的任何方法、變量由你自己來定義,而編寫任務時,你需要實現Runnable接口,把你想讓該任務實現的代碼寫到run方法中,當然,你可以在你定義的任務類中再定義其他變量、方法以在run中調用。
2.代碼實現
public class Task implements Runnable { protected int countDown = 10; private static int taskCount = 0 ; private final int id = taskCount++; public Task(){} public Task(int countDown){ this.countDown = countDown; } public String status(){ return "#"+id+"("+(countDown>0?countDown:"Task!")+"). "; } @Override public void run() { while(countDown-->0){ System.out.print(status()); Thread.yield(); } } }
注:此處代碼源於《thinking in java》
定義了任務,此時並不涉及多線程,所以,任務本身就是一個類,它的對象我們可以在任意試用到的地方調用,例如:
public class TaskMain { public static void main(String[] args){ Task task = new Task(); task.run(); } }
就是在main中聲明了該實例的對象,並調用了它的run方法,同我們平時創建類一樣來調用對象的方法即可。
至此,一個任務定義完了。也就是說按照java的要求,我們實現了一個簡單的任務。然而,實現任務的目的不只是為了實現任務,而是為了讓多線程機制能夠調用該任務去執行。請看:Java多線程——<二>將任務交給線程,線程聲明