一、進程和線程的基礎知識
1、進程和線程的概念
進程:運行中的應用程序稱爲進程,擁有系統資源(cpu、內存)
線程:進程中的一段代碼,一個進程中可以有多段代碼。本身不擁有資源(共享所在進程的資源)
在java中,程序入口被自動創建爲主線程,在主線程中可以創建多個子線程。
區別:
1、是否佔有資源問題
2、創建或撤銷一個進程所需要的開銷比創建或撤銷一個線程所需要的開銷大。
3、進程爲重量級組件,線程爲輕量級組件
多進程: 在操作系統中能同時運行多個任務(程序)
多線程: 在同一應用程序中有多個功能流同時執行
2、線程的主要特點
①、不能以一個文件名的方式獨立存在在磁盤中;
②、不能單獨執行,只有在進程啓動後纔可啓動;
③、線程可以共享進程相同的內存(代碼與數據)。
3、線程的主要用途
①、利用它可以完成重複性的工作(如實現動畫、聲音等的播放)。
②、從事一次性較費時的初始化工作(如網絡連接、聲音數據文件的加載)。
③、併發執行的運行效果(一個進程多個線程)以實現更復雜的功能
4、多線程(多個線程同時運行)程序的主要優點
①、可以減輕系統性能方面的瓶頸,因爲可以並行操作;
②、提高CPU的處理器的效率,在多線程中,通過優先級管理,可以使重要的程序優先操作,提高了任務管理的靈活性;另一方面,在多CPU系統中,可以把不同的線程在不同的CPU中執行,真正做到同時處理多任務。
二、線程的創建和啓動
其實看看API,從Thread的構造方法,就可以看出創建一個線程的方式:
Thread() 分配新的 Thread 對象。 |
Thread(Runnable target) 分配新的 Thread 對象。 |
Thread(Runnable target,String name) 分配新的 Thread 對象。 |
Thread(String name) 分配新的 Thread 對象。 |
Thread(ThreadGroup group,Runnable target) 分配新的 Thread 對象。 |
Thread(ThreadGroup group,Runnable target,String name) 分配新的 Thread 對象,以便將 target 作爲其運行對象,將指定的 name 作爲其名稱,並作爲 group 所引用的線程組的一員。 |
Thread(ThreadGroup group,Runnable target,String name,
long stackSize) 分配新的 Thread 對象,以便將 target 作爲其運行對象,將指定的 name 作爲其名稱,作爲 group 所引用的線程組的一員,並具有指定的堆棧大小。 |
Thread(ThreadGroup group,String name) 分配新的 Thread 對象。 |
後面4個構造方法創建一個線程並加入到一個線程組中,但是創建線程的方式和前面的相似。
java中創建一個線程有兩種方式:
1、繼承Thread類,重寫run()方法,然後直接new這個對象的實例,創建一個線程的實例。然後調用start()方法啓動線程
2、實現Runnable接口,重寫run()方法,然後調用new Thread(runnable)的方式創建一個線程,然後調用start()方法啓動線程
其實看Thread的源文件,發現它也是實現了Runnable接口的。
- public class Thread implements Runnable
1、繼承Thread類的方式
- public class Test1 {
- public static void main(String[] args) {
- System.out.println(Thread.currentThread().getName());
- MyThread myThread=new MyThread();
- myThread.start();
- }
- }
- class MyThread extends Thread{
- int i=0;
- @Override
- public void run() {
- while (i<10) {
- System.out.println(this.getName()+" i的值 "+i);
- i++;
- }
- }
- }
2、實現Runnable接口
- public class Test1 {
- public static void main(String[] args) {
- System.out.println(Thread.currentThread().getName());
- Thread thread=new Thread(new MyRunnable());
- thread.start();
- }
- }
- class MyRunnable implements Runnable{
- int i=0;
- @Override
- public void run() {
- while (i<10) {
- System.out.println(Thread.currentThread().getName()+" i的值 "+i);
- i++;
- }
- }
- }
注意:
①、在繼承Thread的方式中,可以使用getName()方法,來獲得當前線程的名字,這是因爲在Thread類中,有這個方法。可是在實現Runnable方式中,卻不可以使用this.getName(),因爲Runnable接口沒有這個方法(可以看出來,因爲我們沒有提示我們需要重寫這個方法),所以只能通過Thread的靜態方法Thread.currentThread()取得當前的Thread對象,在調用getName()方法,來取得當前線程的名字。
②、對Java來說,run()方法沒有任何特別之處。像main()方法一樣,它只是新線程知道調用的方法名稱(和簽名)。因此,在Runnable上或者Thread上調用run方法是合法的。但並不啓動新的線程。只有調用start()方法纔會啓動新線程。
3、兩種方式的對比
採用實現Runnable接口方式的多線程具有優勢,一般都會使用這種方式:
1、線程類只是實現了Runnable接口,還可以繼承其他類。
2、在這種方式下,可以多個線程共享一個Runnable target對象,所以非常適合多個相同線程來處理同一份資源的情況,從而可以將CPU、代碼和數據分開,形成清晰的模型,較好的體現了面向對象的思想。