一、什么是線程
線程是一個程序內部的順序控制流。
線程和進程
1.進程:每個進程都有獨立的代碼和數據空間,進程切換開銷大。
2.線程:輕量的進程,同一個線程共享代碼和數據空間,每個線程有獨立運行的棧和程序計數器(PC),線程切換的開銷小。
3.在操作系統中能同時運行多個任務(程序)。
4.在同一應用程序有多個順序流同時執行。
問題:對于單核的CPU,處理多個任務時。并不會同時真正的運兩個以上的程序。那么它是怎樣做到處理多任務的呢?
解答:實際上是操作系統負責對處理器就是CPU等資源進行分配組織和管理。實際上每一時刻只能做一件事,或者運行某一個程序。由于在操作系統的管理下,CPU的處理功能被以非常小的時間間隔進行劃分、進行交替,每一個小的時間間隔我們稱為時間片。當時間片到期之后將去執行下一個程序。由于交替的速度非常的快,這樣就給人一種同時運行多個應用程序或者同時做多件事的一種感覺。這種情況我們稱為并發執行。也就是假的,模擬的,通過快速的交替,表現成在同時做多件事。
并行執行才是真正意義上的同一時刻做多個事情,同一個瞬間運行不同的應用程序。這樣就要求有多個CPU。支持程序并發運行的操作系統我們稱為多任務的操作系統或者說是多進程的操作系統。
并發性的工作原理還可以應用在更高的層面上,我們可以在一個應用程序的內部,把它要完成的任務分解為多個更小的子任務以多條齊頭并進的線索來并發的執行,這種就稱為線程或多線程。
二、線程的概念模型
Java語言實現或支持多線程的工作方式。
一個線程必須具備以下三方面的要素才能正常的工作。
1.虛擬的CPU,由java.lang.Thread類封裝和虛擬。
2.CPU所執行的代碼,傳遞給Thread類的對象。
3.CPU所處理的數據,傳遞給Thread類的對象。
三、創建線程
第一種方式:使用Runnable接口創建線程
1.Java的線程是通過java.lang.Thread類來實現。
2.每個線程都是通過某個特定的Thread對象所對應的run()方法來完成其操作。方法run()稱為線程體。
例1:
public class Thread1{
public static void main(String[] args){
Runner1 r=new Runner1();//2.創建實現Runnable接口的對象
Thread t=new Thread(r); //3.創建一個Thread類的對象
t.start(); //4.啟動線程
}
}
class Runner1 implements Runnable{//1.Runner1實現Runnable接口
public void run(){
for(int i=1;i<20;i++){
System.out.println(i);
}
}
}
程序運行的結果是輸出1到19個數字。與在main()方法中直接寫for循環是一樣的效果。
但實現的原理不一樣。
使用線程輸出的有兩個線程(main()主線程和t子線程),不使用只有一個線程。
創建線程的三個步驟
1.定義一個類實現Runnable接口,重寫接口中的run()方法。在run()方法中加入具體的任務代碼或處理邏輯。
2.創建Runnable接口實現類的對象。
3.創建一個Thread類的對象,需要封裝前面Runnable接口實現類的對象。(接口可以實現多繼承)
4.調用Thread對象的start()方法,啟動線程
第二種方式:直接繼承Thread類創建對象
例2:
public class Thread2{
public static void main(String[] args){
Thread t=new Runner2();
t.start();
}
}
class Runner2 extends Thread{
public void run(){
for(int i=1;i<20;i++){
String s=Thread.currentThread().getName();
System.out.println(s+":"+i);
}
}
}
1.首先定義一個類去繼承Thread父類,此時Runner2類并沒有直接的實現Runnable接口,但其實Thread類在JDK中已經實現了Runnable接口。這樣就Runner2類間接的實現了Runnable接口。重寫父類中的run()方法。在run()方法中加入具體的任務代碼或處理邏輯。
2.直接創建一個Runner2類的對象,也可以利用多態性,變量t聲明為父類的類型。
3.線程t啟動,隱含的調用run()方法。
比較兩種方式:
a.使用Runnable接口創建線程
1.可以將CPU,代碼和數據分開,形成清晰的模型
2.線程體run()方法所在的類可以從其它類中繼承一些有用的屬性和方法
3.有利于保持程序的設計風格一致
b.直接繼承Thread類創建對象
1.Thread子類無法再從其它類繼承(java語言的單繼承)。
2.編寫簡單,run()方法的當前對象就是線程對象,可直接操作。