1、什麼是進程、線程、多線程 ?
操作系統中,進程是分配和調度系統資源的最小單位,而線程是進程中的能獨立執行的最小單元 ;
一個進程中至少有一個線程,稱爲主線程,主線程還能創建其他線程,所有線程稱爲多線程 ;
在單核CPU操作系統中,多個線程或者進程採用時間片轉輪的搶佔式方式或取CPU,由於單個時間片很短,給人的感覺就像是多個進程或線程在同時執行,這是僞並行;
在多核CPU操作系統中,線程或進程數小於CPU數量,那麼足以每個進程或者線程各分配一個CPU同時運行,實現真正的並行 。
2、 JVM 線程與操作系統的線程啥關係 ?
先理解 線程模型
- 內核級別線程
內核級別線程(Kernel-level threading)是指用戶進程通過內核提供API創建的線程。這樣用戶進程裏的線程和內核調度的線程是1:1對應的。這也就最簡單的線程管理方法。
- 用戶級別線程
用戶基本線程(User-level threading)是指 用戶進程自己實現線程機制。在這種情況下,內核是不知道有多少線程存在的,同時線程上下文切換更快,而且在不支持多線程的操作系統上也能實現多線程。但是,用戶級別的線程也帶來相當大的壞處,比如不能充分利用多處理器(多核)系統;如果進程中的一個線程執行阻塞的I/O請求,那麼整個用戶進程都會被阻塞。
- 混合線程
混合線程是內核級別線程和用戶級別線程的混合體,提供了以上兩種模型的優點,但是帶來很大的複雜性。
JVM 1.1之前使用的是 用戶級別線程,又稱綠色線程 。
JVM 1.1之後,由於用戶級別線程的侷限性,之後改爲映射內核級別線程 或者進程 。
在linux2.6之前,操作系統還沒有線程,當時映射的是進程和微進程,微進程能進行一定的互相通信,進程之間是完全不能互相通信的 。
linux 2.6 之後,就是目前的,就都是內核級別線程了。
3、java 線程的創建(2種方式)
閱讀java.lang.Thread類的源碼:
private Runnable target;
@Override
public void run() {
if (target != null) {
target.run();
}
}
很明顯,如果我們要創建一個能跑自己邏輯的Thread,就只有2個途徑
1、爲屬性target賦值一個實現了Runnable對象,該對象實現了自己的run方法 。而這個賦值沒有set方法,只有一個途徑,構造函數(源碼如下)
public Thread(Runnable target) {
init(null, target, "Thread-" + nextThreadNum(), 0);
}
2、類繼承Thread,並且重寫run方法 。
示例如下 :
/**
* 線程基礎一:線程的創建
* @author xubo
*
*/
public class ThreadStudyOne {
/**
* 通過Thread(Runnable A)進行創建
*/
private static Thread getThreadFromRunnable() {
return new Thread(new Runnable() {
@Override
public void run() {
//what you want to do !
System.out.println("這是通過Thread(Runnable A)構造函數創建的");
}
});
}
/**
* 繼承
*/
public static class myThread extends Thread {
@Override
public void run() {
//what you want to do !
System.out.println("這是通過重寫父類Thread的run方法創建的");
}
}
private static Thread getThreadFromOverride() {
return new myThread();
}
}
4、進程的調度 ,必須使用Thread.start()方法,直接使用run方法是沒有創建線程的 。
源碼如下
public synchronized void start() {
/**
* This method is not invoked for the main method thread or "system"
* group threads created/set up by the VM. Any new functionality added
* to this method in the future may have to also be added to the VM.
*
* A zero status value corresponds to state "NEW".
*/
if (threadStatus != 0)
throw new IllegalThreadStateException();
/* Notify the group that this thread is about to be started
* so that it can be added to the group's list of threads
* and the group's unstarted count can be decremented. */
group.add(this);
boolean started = false;
try {
start0();
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
/* do nothing. If start0 threw a Throwable then
it will be passed up the call stack */
}
}
}
private native void start0();
5、Thread常用方法 與 屬性
a、先級 priority :
有get與set方法 ,有低中高3個常量,Thread.MIN_PRIORITY=0,Thread.NORM_PRIORITY=5,THREAD.MAX_PRIORITY=10
b、執行 start() :
調用操作系統內核API創建一個線程進行執行任務 。
c、停止 stop() :
調用瞬間,對應線程拋出ThreadDeathException,導致線程異常終止,會有監視器(鎖對象)未釋放的風險,
目前在JDK中標記爲過時
d、打斷 interrupt() :
調用interrupt()方法,對應線程如果處於sleep睡眠狀態,會直接跑出Interrupted異常,否則對應線程
繼續執行,只是狀態改爲了打斷狀態 。這個方法只能終止睡眠狀態線程,使用時根據需要考慮stop()與interrup()。
e、睡眠 sleep ():
sleep(Long m) 表示睡眠多少毫秒 。 如果是sleep(0),表示希望系統直接進行一次CPT資源搶佔分配 ,
給低優先級線程一個運行的機會。該方法不會釋放鎖。
f、暫停 與 喚醒 wait() ,notify(),notifyAll(),yield() :
wait(Long m) : 線程阻塞並釋放鎖,直到被notify()或notifyAll喚醒 ,或者等待m毫秒時間。
wait() : 線程阻塞並釋放鎖,知道被notify()或notifyAll喚醒,否則一直等待
yield() : 線程阻塞並釋放鎖,知道線程組裏面的其他線程執行完成再執行本線程。
g、線程組 ThreadGroup :
對線程進行了隔離 。 只有同一線程組內的線程才能夠互相調用與阻塞。不自己設置線程組的情況下,
都是繼承創建該線程的線程組。以此向上推,可知,同一個線程源頭創建的線程一般都屬於一個線程組。
是否有權限操作某線程a,可用a.checkAccess()方法。
h、執行等待 join() :
join(Thread A) , 強制在A線程執行完後再繼續執行本線程。
i、守護線程
與基本線程其實也沒是區別,
主要特性2點:作用是爲被守護的線程提供監控和服務;會因爲所有被守護的線程的結束而自動結束。
調用setDaemon()方法就能設置守護線程了,在守護線程中創建的線程都是守護線程。