【【線程】】
進程:是一個正在執行中的程序。
每一個進程執行都有一個執行順序,該順序就是一個執行路徑、或者叫一個控制單元
【線程】:就是進程中的一個獨立的控制單元。線程在控制着進程的執行
一個進程中至少有一個線程。(至少一個控制單元)
(在某一個時刻cpu 只能執行一個程序,cpu 在不停的切換。
一個進程當中,可以有多條路徑。
線程是進程中的內容,)
java JVM 啓動的時候會有一個進程java.exe
該進程中至少有一個線程,在負責java程序的執行,
而且,這個線程運行的代碼存在與main方法中。
該線程稱之爲主線程。
擴展:其實更細節說明jvm,jvm啓動不止一個線程,還有複雜垃圾回收機制的線程
【多線程存在的意義】:
【自定義線程】:
1、通過API的查找,java已經提供了對線程這類事物的描述,就是Thread類
創建線程的第一種方式:繼承Thread。
【【步奏】】:
【方法一】:
1、定義類繼承Thread
2、複寫Thread類中的run方法
複寫的目的是將自定義的代碼存儲在run 方法中,讓線程運行。
3、調用線程的start方法
發現,運行結果每一次都不同。
因爲多個線程都在獲取cpud 執行權,cpu執行到誰,誰就運行。
明確一點,在某一個時刻,只能有一個程序在運行。(多核除外)
cpu在做着快速的切換,達到看上去同時運行的效果。
我們可以形象的把多線程的運行行爲看作互相搶奪cpu的執行權
誰搶到誰執行。
這就是多線程的一個特性:隨機性,誰搶到誰執行,至於執行多長,cpu說了算。
爲什麼要覆蓋run(); 方法
Thread 類用於描述線程。
該類就定義了一個存儲線程要運行的代碼,該存儲功能就是run方法
也就是說Thread類中的run 方法用於存貯線程要運行的代碼。
【【步奏】】:
【方法二】:【必須記住】
1、定義類實現Runnable接口
2、覆蓋Runable 接口中 run 方法
3、通過Thread 類建立線程對象。
4、將Runable 接口中 子類對象作爲事件參數傳遞
--------------------------------------------------------------------------------
例子:
//方法一
class Demo extends Thread{
public void run(){
for(int i=0;i<60;i++){
System.out.println("run"+i);
}
}
}
class ThreadDemo{
public lstatic void main(String []args){
Demo d=new Demo();//這樣創建對象的同時就創建了線程
d.start();//開啓並執行線程
//d.run;//僅僅是對象調用方法,而線程創建了,並沒有運行。
/*
Demo 繼承Thread類 並重載run方法後,在main發放中創建一個對象也就創建好一個線程了。
想要調用就得使用到start方法。
*/
for(int i=0;i<60;i++){
System.out.println("main"+i);
}
}
}
--------------------------------------------------------------------------------------
/*自定義多線程的【第二種方式】
*
* 需求:簡單的賣票窗口程序
* 多個窗口同時賣票。
*
* 方式二:實現Runnable 接口
* 步奏:
* 1、定義類實現Runnable 接口
* 2、覆蓋Runnable接口中的run 方法
* 將線程要運行的代碼存放在該run方法中
* 3、通過Thread 類建立線程對象
* 4、將Runnable 接口的子類對象作爲實際參數傳遞給Thread 類的構造函數
* 爲什麼要將Runnable接口的子類對象傳遞給Thread的構造函數,
* 因爲,自定義的run方法所屬的對象是Runnable接口的子類對象。
* 所以要讓線程去指定對對象的run方法
* 5、調用Thread 類的start方法開啓線程並調用Runnable 接口子類的run方法。
*
* 實現方式和繼承方式有什麼【區別】呢
* 實現方式好處:避免了單繼承的侷限性
* 在定義線程時:建議使用實現方式。
*
* 兩種方式的區別:
* 繼承Thread:線程代碼存放在Thread 子類run方法中
* 實現Runnable,線程代碼存放在接口的子類run方法中。
*/
//class Ticket extends Thread{//方式一
//private static int tick=100;//不推薦使用static 因爲他的生命週期太長
class Ticket implements Runnable{//方式二
private int tick=100;
public void run(){
while(true){
if(tick>0)
System.out.println(Thread.currentThread().getName()+"買票"+(tick--));
}
}
}
public class D_Th_test2 {
public static void main(String[] args) {
/* 方式一
Ticket t=new Ticket();
Ticket t2=new Ticket();
Ticket t3=new Ticket();
t.start();
t2.start();
t3.start();
*/
//方式二
Ticket t=new Ticket();//這只是創建對象
Thread t1=new Thread(t);
Thread t2=new Thread(t);
Thread t3=new Thread(t);
t1.start();
t2.start();
t3.start();
/*把Runnable 子類對象當作參數傳遞給Thread方法的構造函數,
* 通過調用Thread類的start方法開啓線程並調用Runnable中的run方法
*/
}
}
----------------------------------------------------------------
/*//方式二
* Test4 學習【同步】以後再回來看該代碼
*/
class Ticket2 implements Runnable{
private int tick=100;
public void run(){ //run是不能直接改爲同步函數的,因爲while不需要同步,上鎖後會出現一直循環打印的結果,那麼
while(true){
//if(tick>0)
// System.out.println(Thread.currentThread().getName()+"買票"+(tick--));
show();//設置同步函數後
}
}
public synchronized void show(){// 把該函數改爲同步函數即可
//複製代碼到此後,註釋掉run中代碼
if(tick>0)
System.out.println(Thread.currentThread().getName()+"買票"+(tick--));
}
}
黑馬官網: http://edu.csdn.net/heima