Java多線程
- 程序
- 線程
-
- 線程的生命周期
- 建立線程
- 線程的優先級
- 線程排程器
程序
正在運作中的程式。每個程序都擁有自己(獨立)的系統資源、記憶體空間和位址空間
線程
線程是作業系統能夠進行運算排程的最小機關,它被包含在程序之中,是程序中的實際運作機關。
線程的生命周期
建立狀态(new )、可運作狀态(runnable)、運作狀态(running )、阻塞狀态(blocked)、終止狀态(dead)
- 當線程處于建立狀态的時候,表明此時線程的對象執行個體已經被建立,但是尚未取得運作線程所需要的資源
- 産生了對象的執行個體之後,一旦調用線程的start()方法,則線程就會進入可運作狀态,表明該線程已經獲得運作時所需要的系統資源,具備了被排程執行的條件,進而使該線程可以被排程執行。
- 線程的運作狀态是指線程被JVM線程排程程式配置設定了CPU執行時間,使用run() (在執行了start()之後,,run()自啟動)方法可以使線程進入運作狀态。正在運作的線程随時可能由JVM線程排程程式送回可運作狀态。
- 當線程的run()方法執行完畢後進入終止狀态,處于該狀态的線程不會再被排程執行。
- 阻塞狀态通常用于線程之間的通信與同步控制。
建立線程
Java程式中的線程被設計為一個對象,該對象具有自己的生命周期,可以利用接口java.lang.Runnable、類java.lang.Thread、Callable接口 建立一個線程
通過java.lang.Thread建立線程
繼承Thread類,重寫 run() 方法(必須重寫)
public class ThreadDemo extends Thread {
@Override
public void run() {
System.out.println("目前線程的是:"+this.getName());
}
public static void main(String[] args) {
ThreadDemo threadDemo = new ThreadDemo();
threadDemo.start();
}
}
- 優點:程式代碼相對簡單,缺點:java 單繼承使用場景限制
實作Runnable接口,實作 run() 方法
public class RunnableDemo implements Runnable {
@Override
public void run() {
System.out.println("目前線程的是:"+Thread.currentThread().getName());
}
public static void main(String[] args) {
RunnableDemo runnableDemo = new RunnableDemo();
new Thread(runnableDemo).start();
}
}
Runnable建立線程:通過把Runnable的一個子類的執行個體作為參數傳遞 給Thread類的一個構造方法
優點:
- 符合面向對象的設計思想
從面向對象的設計角度看,Thread類是虛拟CPU 的封裝,因而Thread類的子類是關于CPU行為的類,但是在繼承Thread類的子類大多都是與CPU不相關的類,而實作Runnable接口的方法将不會影響到Thread體系
- 實作了Runnable接口的類可以 用extends繼承其他的類
Callable接口建立線程:實作Callable 接口,使用FutureTask 進行包裝,通過Thread的構造方法傳入futureTask執行個體
package com.callable;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.FutureTask;
public class ICallableTest implements Callable<Long> {
@Override
public Long call() {
Long id = Thread.currentThread().getId();
System.out.println("目前的線程是"+Thread.currentThread().getName());
return id;
}
public static void main(String[] args) throws ExecutionException, InterruptedException {
ICallableTest ct = new ICallableTest();
FutureTask futureTask = new FutureTask(ct);
Thread t = new Thread(futureTask,"二貨");
t.start();
System.out.println(futureTask.get());
}
}
實作Callable接口的 call() 方法是帶傳回值(方法體中必須return )的,通過futureTask的 get() 獲得

Callable和Runnable 的差別:
- Runnable的 run() 方法沒有傳回值,而Callable得 call() 方法有傳回值,且支援泛型
- Runnable 接口 的 run() 方法隻能抛出運作時候得異常,且無法捕獲處理;Callable 接口 call 方法允許抛出異常(throws Exception),可以擷取異常資訊
線程的優先級
線程優先級是指優先級越高,越有可能先執行,但隻是建議先執行,具體什麼時候執行由系統決定(既不能絕對的說線程的排程是按照優先級進行排程的)
例如在windows系統中,當一個優先級為5且處于可運作狀态的線程在等待CPU資源的時,系統可能正在執行一個優先級為3的線程
- 設定線程的優先級
public final void setPriority(int newPriority) ;
- 擷取線程的優先級
public final int getPriority( );
- 在Thread 類中定義了線程優先級的取值範圍(1~10)
//靜态成員變量
public static final int MIN_PRIORITY = 1;
public static final int NORM_PRIORITY = 5;
public static final int MAX_PRIORITY = 10;
優先級高隻是建議先執行
Priority.java
public class Priority extends Thread {
public Priority(String s){
setName(s);
}
public void run(){
System.out.println("線程:"+getName()+"----"+getPriority());
}
}
PriorityTest.java
public class PriorityTest {
public static void main(String[] args){
Priority p1 = new Priority("線程 1");
Priority p2 = new Priority("線程 2");
Priority p3 = new Priority("線程 3");
Priority p4 = new Priority("線程 4");
p1.setPriority(1);
p2.setPriority(2);
p3.setPriority(3);
p4.setPriority(4);
p1.start();
p2.start();
p3.start();
p4.start();
}
}
線程排程器
Java提供了一個線程排程器來監視所有程式中的所有運作的線程,并決定哪個線程應該運作,哪個線程應該排隊等待。線上程的 排程器的決策過程中,它可以識别線程的兩個特征:一個是線程的優先級别,另一個是守護标志
- 守護線程:一般具有一個較低的優先級别,并且當計算機中運作的線程減少的時,為一個或多個程式提供一項基本的服務。例如垃圾收集線程就是一個不斷運作的守護線程,它由于JVM提供,通過掃描程式查找不再被通路的變量,并把這些變量的資源釋放給系統
- 排程器的基本原則:如果隻有守護線程在運作,JVM将退出。新線程将從建立它的線程那裡繼承優先級别和守護标志,排程器通過分析所有線程的優先級來決定哪個線程先運作。具有較高優先級的線程,能夠在較低優先級的 線程之前執行(但并不絕對)。