一:Thread是什麼
執行緒Thread是程式中的一個實體,是被系統獨立排程和分派的基本單位,執行緒自己不擁有系統資源,只擁有一點在執行中必不可少的資源,但它可與同屬一個程式的其它執行緒共享程式所擁有的全部資源。 Java程式執行時,會啟動一個JVM程式,JVM尋找到程式的入口main(),會建立一個主執行緒執行。一個java程式至少有一個程式,一個程式至少有一個執行緒。
二:執行緒的建立與使用
- 繼承Thread,重寫run方法
class MyThread extends Thread {
@Override
public void run() {
// do something
super.run();
}
}
MyThread myThread = new MyThread();
myThread.start();
複製程式碼
- 實現Runnable介面
class MyRunnable implements Runnable {
@Override
public void run() {
// do something
}
}
Thread thread = new Thread(new MyRunnable());
thread.start();
複製程式碼
三:執行緒的狀態
- 執行緒的狀態標誌
public enum State {
NEW,
RUNNABLE,
BLOCKED,
WAITING,
TIMED_WAITING,
TERMINATED;
}
複製程式碼
- NEW 執行緒剛剛建立,尚未啟動
- RUNNABLE 執行緒正在執行
- BLOCKED 執行緒堵塞狀態,等待同步塊的鎖的釋放,如果獲得鎖,就會自動進入執行狀態
- WAITING 執行緒處於等待狀態,需要被其他執行緒喚醒(notify、notifyAll方法的呼叫)。執行緒在呼叫了join之後,也會進入等待狀態,直到被join的執行緒執行結束才會被喚醒
- TIMED_WAITING 有限時間的等待,一般出現在呼叫sleep(time),join(time),sleep(time)後
- TERMINATED 執行緒執行結束
- 執行緒的狀態轉換
四:執行緒的基本屬性
private volatile String name; // 執行緒名稱
private int priority; // 優先順序,1~10
private boolean daemon = false; // 是否是守護執行緒
private Runnable target; // 實際被執行的物件
ThreadLocal.ThreadLocalMap threadLocals = null; // 當前執行緒的資料
private long tid; // 執行緒id
複製程式碼
五:執行緒建立初始化
private void init(ThreadGroup g, Runnable target, String name, long stackSize) {
// 獲取當前執行緒,給新建立的執行緒設定執行緒組
Thread parent = currentThread();
if (g == null) {
g = parent.getThreadGroup();
}
// ThreadGroup nUnstartedThreads++;
g.addUnstarted();
this.group = g;
this.target = target;
this.priority = parent.getPriority(); // 使用父執行緒的優先順序
this.daemon = parent.isDaemon(); // 使用父執行緒的屬性,是否是守護執行緒
setName(name);
init2(parent);
/* Stash the specified stack size in case the VM cares */
this.stackSize = stackSize;
tid = nextThreadID();
}
複製程式碼
六:主要方法
public synchronized void start() {
// 判斷狀態,只能啟動一次
if (threadStatus != 0 || started)
throw new IllegalThreadStateException();
group.add(this);
started = false;
try {
nativeCreate(this, stackSize, daemon);
started = true;
} finally {
try {
if (!started) {
group.threadStartFailed(this);
}
} catch (Throwable ignore) {
}
}
}
// 執行方法,target是實際可執行的Runnable物件
public void run() {
if (target != null) {
target.run();
}
}
// 退出
private void exit() {
// 將當前執行緒衝ThreadGroup裡面移除
if (group != null) {
group.threadTerminated(this);
group = null;
}
target = null;
threadLocals = null;
inheritableThreadLocals = null;
inheritedAccessControlContext = null;
blocker = null;
uncaughtExceptionHandler = null;
}
// 執行緒中斷
public void interrupt() {
if (this != Thread.currentThread())
checkAccess();
synchronized (blockerLock) {
Interruptible b = blocker;
if (b != null) {
nativeInterrupt();
b.interrupt(this);
return;
}
}
nativeInterrupt();
}
public final void join(long millis) throws InterruptedException {
synchronized(lock) {
long base = System.currentTimeMillis();
long now = 0;
if (millis < 0) {
throw new IllegalArgumentException("timeout value is negative");
}
if (millis == 0) {
while (isAlive()) {
lock.wait(0);
}
} else {
while (isAlive()) {
long delay = millis - now;
if (delay <= 0) {
break;
}
lock.wait(delay);
now = System.currentTimeMillis() - base;
}
}
}
}
public static native void yield();
複製程式碼
小結:
- 什麼是守護執行緒?
守護執行緒與普通執行緒的唯一區別是:當JVM中所有的執行緒都是守護執行緒的時候,JVM就可以退出了;如果還有一個或以上的非守護執行緒則不會退出。(以上是針對正常退出,呼叫System.exit則必定會退出)
建立守護執行緒,thread.setDaemon(true);必須在start()之前呼叫。
參考:守護執行緒與普通執行緒
-
ThreadLocal
-
sleep
sleep使當前執行緒暫停,並沒有釋放鎖,經過傳入的time時間後自動繼續執行。 -
yield
暫停當前執行緒,讓其它優先順序大於等於該執行緒的執行緒有機會先執行,不過不能保證該執行緒能夠立即停止。 -
join
當前執行緒暫停,等待插入的執行緒執行完畢之後繼續執行。 -
interrupt
執行緒中斷,只是設定了一箇中斷標誌,線上程中使用者自己獲取這個標誌然後自己退出。