學習Thread的第一天就知道要調用Thread的start方法,不要調用Thread額run方法,爲什麼呢?
新建一個Thread類的實例,然後調用run方法,相當於調用普通的方法,屬於當前線程的一個方法執行,可以重複多次調用,run方法運行結束, 此線程終止, 而CPU再運行其它線程。
run()方法當作普通方法的方式調用,程序還是要順序執行,還是要等待run方法體執行完畢後纔可繼續執行下面的代碼;如果直接用run方法, 這只是調用一個方法而已, 程序中依然只有主線程這一個線程, 其程序執行路徑還是隻有一條。上面的結論可以得出線程的模型,線程棧是指某時刻時內存中線程調度的棧信息,當前調用的方法總是位於棧頂。當調用Thread的start方法時會生成新的線程,放在單獨的線程棧中。
調用start的方法有什麼不同呢,調用了start的方法會創建線程,並自動調用run方法:
/**
* Causes this thread to begin execution; the Java Virtual Machine
* calls the <code>run</code> method of this thread.
* <p>
* The result is that two threads are running concurrently: the
* current thread (which returns from the call to the
* <code>start</code> method) and the other thread (which executes its
* <code>run</code> method).
* <p>
* It is never legal to start a thread more than once.
* In particular, a thread may not be restarted once it has completed
* execution.
*
* @exception IllegalThreadStateException if the thread was already
* started.
* @see #run()
* @see #stop()
*/
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中的線程都是stared*/
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();
根據上面Thread 中start方法的註釋,調用Thread的start方法後會創建一個線程(不同於調用start的當前線程的線程),此時線程還沒有運行,是可運行的狀態(新建線程的狀態)。線程最終會調用本地方法start0,它的內部最終會調用run方法。JVM會在線程啓動時調用run方法,此時的線程才處於運行狀態。run方法結束時,線程終止。
一個線程只能調用start()方法一次,多次啓動一個線程是非法的,因爲線程的狀態變化從new到running不可逆轉,且只會發生一次。
看源碼 if (threadStatus != 0)
throw new IllegalThreadStateException();
當重複調用時threadStatus != 0 會拋出異常。
Thread 被添加進了group, ThreadGroup group;
線程一定屬於某一個線程組中,線程組中可以有線程對象,也可以有線程組,組中還可以有線程,是一種類似屬性結構的結構。
Thread 方法:
activeCount 獲取當前線程所有活動線程的估計數,因爲線程數量是實時改變的。
enumerate把所有活動線程放入到tarray中。
獲取當前main線程內的所有的線程:
package com.sync.demo;
import java.util.concurrent.Callable;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
public class Demo1 {
public static void main(String[] args) {
ThreadDemo demo1 = new ThreadDemo();
demo1.setName("demo1");
demo1.start();
Thread thread2 = new Thread(new RunnableDemo());
thread2.setName("demo1");
thread2.start();
FutureTask<String> thread3 = new FutureTask<>(new Callable<String>() {
@Override
public String call() throws Exception {
try {
Thread.sleep(3000);
} catch (Exception e) {
// TODO: handle exception
}
return "demo3";
}
});
new Thread(thread3).start();
//or Executors.newSingleThreadExecutor().execute(thread3);
findAllThread();
}
public static class ThreadDemo extends Thread{
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("demo1");
}
}
public static class RunnableDemo implements Runnable{
@Override
public void run() {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
System.out.println("demo2");
}
}
public static Thread[] findAllThread(){
ThreadGroup currentGroup =Thread.currentThread().getThreadGroup();
//找到最終的父線程組
while (currentGroup.getParent()!=null && currentGroup.getParent().getName().equals("main")){
currentGroup=currentGroup.getParent();
}
//活動線程的估計數
int noThreads = currentGroup.activeCount();
Thread[] threadArray = new Thread[noThreads];
//複製到指定數組中。
currentGroup.enumerate(threadArray);
for (Thread thread : threadArray) {
System.out.println("線程數量:"+noThreads+" 線程id:" + thread.getId() + " 線程名稱:" + thread.getName() + " 線程狀態:" + thread.getState());
}
return threadArray;
}
}
Result:
線程數量:4 線程id:1 線程名稱:main 線程狀態:RUNNABLE
線程數量:4 線程id:11 線程名稱:demo1 線程狀態:TIMED_WAITING
線程數量:4 線程id:12 線程名稱:demo1 線程狀態:TIMED_WAITING
線程數量:4 線程id:13 線程名稱:Thread-2 線程狀態:TIMED_WAITING
demo1
demo2