建立多線程第一種方法
建立多線程程式的第一種方式:建立Thread類的子類
java.lang.Thread類:是描述線程的類,我們想要實作多線程程式,就必須繼承Thread類
實作步驟:
1.建立一個Thread類的子類
2.在Thread類的子類中重寫Thread類中的run方法,設定線程任務(開啟線程要做什麼?)
3.建立Thread類的子類對象
4.調用Thread類中的方法start方法,開啟新的線程,執行run方法
void start() 使該線程開始執行;Java 虛拟機調用該線程的 run 方法。
結果是兩個線程并發地運作;目前線程(main線程)和另一個線程(建立的新線程,執行其 run 方法)。
多次啟動一個線程是非法的。特别是當線程已經結束執行後,不能再重新啟動。
java程式屬于搶占式排程,那個線程的優先級高,那個線程優先執行;同一個優先級,随機選擇一個執行
代碼示範
main方法
public class Demo01Thread {
public static void main(String[] args) {
//3.建立Thread類的子類對象
MyThread mt = new MyThread();
//4.調用Thread類中的方法start方法,開啟新的線程,執行run方法
mt.start();
for (int i = 0; i <20 ; i++) {
System.out.println("main:"+i);
}
}
}
MyThread類
//1.建立一個Thread類的子類
public class MyThread extends Thread{
//2.在Thread類的子類中重寫Thread類中的run方法,設定線程任務(開啟線程要做什麼?)
@Override
public void run() {
for (int i = 0; i <20 ; i++) {
System.out.println("run:"+i);
}
}
}
多線程原理
記憶體圖解
執行mt.start就開辟一個新棧,cpu就可以有可以有多個選擇,多個程序互不影響
建立多線程的第二種方法
采用 java.lang.Runnable 也是非常常見的一種,我們隻需要重寫run方法即可。
步驟如下:
- 定義Runnable接口的實作類,并重寫該接口的run()方法,該run()方法的方法體同樣是該線程的線程執行體。
- 建立Runnable實作類的執行個體,并以此執行個體作為Thread的target來建立Thread對象,該Thread對象才是真正 的線程對象。
- 調用線程對象的start()方法來啟動線程。
public class MyRunnable implements Runnable{
@Override public void run()
{ for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+" "+i); } } }
public class Demo {
public static void main(String[] args) {
//建立自定義類對象 線程任務對象
MyRunnable mr = new MyRunnable();
//建立線程對象
Thread t = new Thread(mr, "小強");
t.start();
for (int i = 0; i < 20; i++)
{ System.out.println("旺财 " + i);
} } }
通過實作Runnable接口,使得該類有了多線程類的特征。run()方法是多線程程式的一個執行目标。所有的多線程 代碼都在run方法裡面。Thread類實際上也是實作了Runnable接口的類。 在啟動的多線程的時候,需要先通過Thread類的構造方法Thread(Runnable target) 構造出對象,然後調用Thread 對象的start()方法來運作多線程代碼。 實際上所有的多線程代碼都是通過運作Thread的start()方法來運作的。是以,不管是繼承Thread類還是實作 Runnable接口來實作多線程,最終還是通過Thread的對象的API來控制線程的,熟悉Thread類的API是進行多線程 程式設計的基礎
Thread和Runnable的差別
如果一個類繼承Thread,則不适合資源共享。但是如果實作了Runable接口的話,則很容易的實作資源共享。
總結: 實作Runnable接口比繼承Thread類所具有的優勢:
- 适合多個相同的程式代碼的線程去共享同一個資源。
- 可以避免java中的單繼承的局限性。
- 增加程式的健壯性,實作解耦操作,代碼可以被多個線程共享,代碼和線程獨立。
- 線程池隻能放入實作Runable或Callable類線程,不能直接放入繼承Thread的類
擴充:在java中,每次程式運作至少啟動2個線程。一個是main線程,一個是垃圾收集線程。因為每當使用 java指令執行一個類的時候,實際上都會啟動一個JVM,每一個JVM其實在就是在作業系統中啟動了一個程序。
匿名内部類方式實作線程的建立
使用線程的内匿名内部類方式,可以友善的實作每個線程執行不同的線程任務操作。 使用匿名内部類的方式實作Runnable接口,重新Runnable接口中的run方法:
package 一.線程;
/*
匿名内部類方式實作線程的建立
匿名:沒有名字
内部類:寫在其他類内部的類
匿名内部類作用:簡化代碼
把子類繼承父類,重寫父類的方法,建立子類對象合一步完成
把實作類實作類接口,重寫接口中的方法,建立實作類對象合成一步完成
匿名内部類的最終産物:子類/實作類對象,而這個類沒有名字
格式:
new 父類/接口(){
重複父類/接口中的方法
};
*/
public class 匿名内部類方式實作多線程的建立 {
public static void main(String[] args) {
//線程的父類是Thread
//new MyThread().start();
new Thread(){
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+"-->"+"黑馬");
}
}
}.start();
//線程的接口Runnable
//Runable r = new RunnableImpl
Runnable r = new RunableImpl(){
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+"-->"+"高高高");
}
}
};
//開啟多線程
new Thread(r).start();
//簡化接口的方式 直接在r裡面加一堆
new Thread(new Runnable() {
@Override
public void run() {
for (int i = 0; i < 20; i++) {
System.out.println(Thread.currentThread().getName()+"-->"+"黑馬");
}
}
}).start();
}
}