前面的文章:多線程爬坑之路-學習多線程需要來了解哪些東西?(concurrent並發包的數據結構和線程池,Locks鎖,Atomic原子類)
前面大致的了解了Thread的一些方法和屬性下面對一些方法進行運用看看具體效果<下面可能還是會貼很多的源代碼,其實我是拒絕的,我只想貼每個方法的代碼,但是有時候看到一個方法里面有調用了方法,但是筆者有沒有給出來,很蛋疼,有種爽到一半的感覺,所以我還是會把它貼出來,希望一次就能挖到底,不論有沒有全懂,但至少懂了幾分。>
activeCount():返回當前線程所屬線程組的活動線程數
源代碼如下:
1 /**
2 * Returns an estimate of the number of active threads in the current 3 * thread's {@linkplain java.lang.ThreadGroup thread group} and its 4 * subgroups. Recursively iterates over all subgroups in the current 5 * thread's thread group. 6 * 7 * <p> The value returned is only an estimate because the number of 8 * threads may change dynamically while this method traverses internal 9 * data structures, and might be affected by the presence of certain 10 * system threads. This method is intended primarily for debugging 11 * and monitoring purposes. 12 * 13 * @return an estimate of the number of active threads in the current 14 * thread's thread group and in any other thread group that 15 * has the current thread's thread group as an ancestor 16 */
17 public static int activeCount() { 18 return currentThread().getThreadGroup().activeCount(); 19 }
這個靜態方法先調用了一個currentThread()方法獲取當前線程,然后調用了getThreadgroup()獲取線程組,最后調用了activeCount()方法獲取活動線程數。下面是調用的方法的具體實現,native方法調用的是VM的實現,需要下載VM的源碼才能查看,這里先略過。
/** * Returns a reference to the currently executing thread object. * * @return the currently executing thread. */
public static native Thread currentThread(); /** * Returns the thread group to which this thread belongs. * This method returns null if this thread has died * (been stopped). * * @return this thread's thread group. */
public final ThreadGroup getThreadGroup() { return group; } /** * Returns an estimate of the number of active threads in this thread * group and its subgroups. Recursively iterates over all subgroups in * this thread group. * * <p> The value returned is only an estimate because the number of * threads may change dynamically while this method traverses internal * data structures, and might be affected by the presence of certain * system threads. This method is intended primarily for debugging * and monitoring purposes. * * @return an estimate of the number of active threads in this thread * group and in any other thread group that has this thread * group as an ancestor * * @since JDK1.0 */
public int activeCount() { int result; // Snapshot sub-group data so we don't hold this lock // while our children are computing.
int ngroupsSnapshot; ThreadGroup[] groupsSnapshot; synchronized (this) { if (destroyed) { return 0; } result = nthreads; ngroupsSnapshot = ngroups; if (groups != null) { groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot); } else { groupsSnapshot = null; } } for (int i = 0 ; i < ngroupsSnapshot ; i++) { result += groupsSnapshot[i].activeCount(); } return result; }
方法的使用:
1 /**
2 * thread method test 3 * @author Ljcx 4 * 5 */
6 public class ThreadMethord implements Runnable{ 7 @Override 8 public void run() { 9 System.out.println(""); 10 try { 11 Thread.sleep(1000); 12 } catch (InterruptedException e) { 13 e.printStackTrace(); 14 } 15 } 16
17 public static void main(String[] args) { 18 ThreadMethord tm = new ThreadMethord(); 19 Thread th = new Thread(tm); 20 th.start(); 21 System.out.println("--活動線程數--"+th.activeCount()); 22 ThreadMethord tm2 = new ThreadMethord(); 23 Thread th2 = new Thread(tm2); 24 th2.start(); 25 System.out.println("--活動線程數--"+th2.activeCount()); 26 } 27 }
運行結果:
--活動線程數--2
--活動線程數--3
程序啟動一共創建了三個線程:main,th,th2,主線程啟動main函數,線程th啟動,此時的活動線程為main,th.然后創建線程th2並啟動。此時活動線程數是main,th,th2.把上面的代碼稍微修改一下
1 public class ThreadMethord implements Runnable{ 2 public void run() { 3 System.out.println(""); 4 /*try { 5 Thread.sleep(1000); 6 } catch (InterruptedException e) { 7 e.printStackTrace(); 8 }*/
9 } 10
11 public static void main(String[] args) { 12 ThreadMethord tm = new ThreadMethord(); 13 Thread th = new Thread(tm); 14 th.start(); 15 System.out.println("--活動線程數--"+th.activeCount()); 16 ThreadMethord tm2 = new ThreadMethord(); 17 Thread th2 = new Thread(tm2); 18 th2.start(); 19 System.out.println("--活動線程數--"+th2.activeCount()); 20 } 21 }
運行結果:
1 --活動線程數--2
2 --活動線程數--2
好像跟預期的結果不一樣,只是因為把線程休眠去掉了,那是因為在th2啟動的時候th1已經運行結束了。
基本屬性的獲取方法:
方法使用:
1 public class ThreadMethord implements Runnable{ 2 public void run() { 3 System.out.println(""); 4 System.out.println("-當前線程的引用--"+ Thread.currentThread()); 5 try { 6 Thread.sleep(1000); 7 } catch (InterruptedException e) { 8 e.printStackTrace(); 9 } 10 } 11
12 public static void main(String[] args) { 13 ThreadMethord tm = new ThreadMethord(); 14 Thread th = new Thread(tm); 15 th.start(); 16 System.out.println("--活動線程數--"+th.activeCount()); 17 ThreadMethord tm2 = new ThreadMethord(); 18 Thread th2 = new Thread(tm2); 19 th2.start(); 20 System.out.println("--活動線程數--"+th2.activeCount()); 21 Thread [] tarray = new Thread[3]; 22 System.out.println("-當前線程的引用--"+ Thread.currentThread()); 23 Thread.enumerate(tarray);//將當前線程的所有活動線程放進數組里
24 for (Thread thread : tarray) { 25 System.out.println("--tarray活動線程--"+thread); 26 } 27
28 System.out.println("--th線程ID--"+th.getId()); 29 System.out.println("--th的線程名--"+ th.getName()); 30 System.out.println("--th的線程優先級--"+ th.getPriority()); 31 System.out.println("--th的線程組--"+ th.getThreadGroup()); 32
33
34 System.out.println("--th2線程ID--"+th2.getId()); 35 System.out.println("--th2的線程名--"+ th2.getName()); 36 th2.setPriority(6);//設置優先級
37 System.out.println("--th2的線程優先級--"+ th2.getPriority()); 38 System.out.println("--th2的線程組--"+ th2.getThreadGroup()); 39 } 40 }
運行結果:
1 --活動線程數--2
2 --活動線程數--3
3 -當前線程的引用--Thread[main,5,main] 4
5 --tarray活動線程--Thread[main,5,main] 6 --tarray活動線程--Thread[Thread-0,5,main] 7 --tarray活動線程--Thread[Thread-1,5,main] 8
9 --th線程ID--10
10 --th的線程名--Thread-0
11 --th的線程優先級--5
12 --th的線程組--java.lang.ThreadGroup[name=main,maxpri=10] 13 --th2線程ID--11
14 --th2的線程名--Thread-1
15 --th2的線程優先級--6
16 --th2的線程組--java.lang.ThreadGroup[name=main,maxpri=10] 17
18 -當前線程的引用--Thread[Thread-0,5,main] 19 -當前線程的引用--Thread[Thread-1,6,main]
可以看到主線程他的引用就是main,優先級是5,所屬線程組是main,th和th2他們的引用分別是Thread-0,Thread-1,這是他們的線程名,因為我們在創建現成的時候沒有個他初始化名稱,所以默認使用Thread-加上線程組內線程創建的序號。(說多了我以為我在胡扯,來看一波源代碼)
源代碼:
//這個初始化方法是我們調用的,可以看到他的命名方式:“Thread-“+nextThreadNum(),這個nextThreadNum方法是一個同步的方法,加了
//sychnorized鎖,返回的是一個私有的靜態的int類型的屬性,所以他的默認值應該是0,說到這有的小伙伴可能有疑問了,既然默認值(初始值)0,
//那么這里返回的是threadInitNumber++,那第一個線程名應該是Thread-1,問題又回到了++i和i++的問題了,不多說了。
public Thread(Runnable target) { init(null, target, "Thread-" + nextThreadNum(), 0); } /*初始化方法的四個參數第一個線程組,第二個線程,第三個線程名,第四個是棧大小
private void init(ThreadGroup g, Runnable target, String name,long stackSize) {
init(g, target, name, stackSize, null);
}*/
private static int threadInitNumber; private static synchronized int nextThreadNum() { return threadInitNumber++; }
getState():獲取線程狀態
方法使用:
1 public class TestMethord2 implements Runnable{ 2 @Override 3 public void run() { 4 //獲取當前線程的引用
5 Thread obj = Thread.currentThread(); 6 System.out.println("線程:"+obj.getName()+"的狀態:"+obj.getState());//RUNNABLE 7 try { 8 Thread.sleep(2000); 9 } catch (InterruptedException e) { 10 e.printStackTrace(); 11 } 12 } 13 public static void main(String[] args) { 14 TestMethord2 t1 = new TestMethord2(); 15 TestMethord2 t2 = new TestMethord2(); 16 Thread th1 = new Thread(t1,"th1"); 17 System.out.println(th1.getState());//NEW 18 th1.start(); 19 System.out.println(th1.getState());//RUNNABLE 20 //等待線程執行到sleep
21 try { 22 Thread.sleep(1000); 23 } catch (InterruptedException e) { 24 e.printStackTrace(); 25 } 26 System.out.println(th1.getState());//TIMES_WAITING 27 //等待線程th1執行完畢
28 try { 29 Thread.sleep(1000); 30 } catch (InterruptedException e) { 31 e.printStackTrace(); 32 } 33 System.out.println(th1.getState());//TERMINATED 34 } 35 }
運行結果:(跑一下代碼一目了然可以看到不同的狀態)
1 線程th1的狀態:NEW 2 線程th1的狀態:RUNNABLE 3 RUN線程th1的狀態:RUNNABLE 4 線程th1的狀態:TIMED_WAITING 5 線程th1的狀態:TERMINATED
開始創建的時候狀態是:NEW。start之后線程執行,狀態是RUNNABLE,此時主線程進入休眠1秒,是為了等待th1進入到休眠狀態,當th1進入休眠狀態2秒,主線程已經結束了休眠此時在查看th1的狀態為TIMED_WAIING,我們再讓主線程等待1秒,th1結束了休眠,執行完畢,再次查看th1狀態為TERMINATED。
跟狀態相關的方法:
yield:暫停當前線程,讓其他線程先執行。
1 public class TestMethord3 implements Runnable{ 2
3 @Override 4 public void run() { 5 System.out.println(Thread.currentThread().getName()+"runing....."); 6
7 for (int i = 0; i <10; i++) { 8 System.out.println(Thread.currentThread().getName()+":"+i); 9 if(i==3){ 10 Thread.yield(); 11 } 12 } 13 } 14 public static void main(String[] args) { 15 TestMethord3 tm1 = new TestMethord3(); 16 TestMethord3_2 tm2 = new TestMethord3_2(); 17 Thread th1 = new Thread(tm1, "th1"); 18 Thread th2 = new Thread(tm2, "th2"); 19 th1.start(); 20 th2.start(); 21 } 22 }
1 public class TestMethord3_2 implements Runnable{ 2 public void run() { 3 System.out.println(Thread.currentThread().getName()+"runing....."); 4 for (int i = 0; i < 10; i++) { 5 System.out.println("------------------"+i); 6 } 7 } 8 }
運行結果:這個結果每次運行都不一樣。
1 th2runing..... 2 th1runing..... 3 ------------------0
4 ------------------1
5 ------------------2
6 ------------------3
7 ------------------4
8 ------------------5
9 ------------------6
10 th1:0
11 ------------------7
12 th1:1
13 ------------------8
14 ------------------9
15 th1:2
16 th1:3
17 th1:4
18 th1:5
19 th1:6
20 th1:7
21 th1:8
22 th1:9
按照理想上來說,我們在th1運行到輸出3的時候就應該停下來讓th2先執行完,th1和th2是我交叉執行應該只發生在th1輸出3之前。然而結果並不是如此,多運行幾次就會發現,這個yield方法並沒有起到應有的作用,這是由於CPU資源充足的情況下兩個都能獲取到CPU,暫停當前線程的執行可能只是在CPU資源不足的情況下讓出CPU資源。(個人理解),但是就算是CPU資源不充足,兩個同等優先級的線程在一個暫停之后仍然有同等幾率被調度選中分配到資源,所以說這個yield方法同等優先級的情況下出現不管用的幾率會更大。
join:等待某線程終止
1 public class TestMethord3 implements Runnable{ 2 public void run() { 3 System.out.println(Thread.currentThread().getName()+"runing....."); 4
5 for (int i = 0; i <10; i++) { 6 System.out.println(Thread.currentThread().getName()+":"+i); 7 if(i==3){ 8 Thread.yield(); 9 } 10 } 11 } 12 public static void main(String[] args) throws InterruptedException { 13 TestMethord3 tm1 = new TestMethord3(); 14 TestMethord3_2 tm2 = new TestMethord3_2(); 15 Thread th1 = new Thread(tm1, "th1"); 16 Thread th2 = new Thread(tm2, "th2"); 17 th1.start(); 18 th2.start(); 19 th2.join(); 20 System.out.println("th2的狀態:"+th2.getState()); 21 } 22 } 23
24 public class TestMethord3_2 implements Runnable{ 25 public void run() { 26 System.out.println(Thread.currentThread().getName()+"runing....."); 27 for (int i = 0; i < 10; i++) { 28 System.out.println("------------------"+i); 29 } 30 } 31 }
運行結果:下面是運行四次的結果顯示,從結果中可以看出,無論th1,th2怎么運行,最終主線程輸出的th2的狀態都是TERMINATED,因為這一行輸出是放在th2.join()后面的,表示的是主線程要等待th2執行完畢才能繼續執行。
wait(),wait(long million),notify(),notifyAll(),這幾個方法繼承自Object類.
wait()和wait(long million):指的是讓線程等待,與sleep的不同的是,wait方法會釋放CPU,而sleep仍然占有CPU資源。
notify():指的是喚醒某個線程
notifyAll() :指的是喚醒所有的線程
這幾個方法需要組合使用,在多個線程運行時涉及到的先后問題,暫時還未研究深入,先放一下。后面會補充上。
通過上面這些方法,基本上了解了線程這個類。除去基本的屬性方法,其他的跟狀態相關的在復雜的並發線程環境中才能體現他們的作用和價值,也才能展現出使用上的難度,這里所涉及到的不過是九牛一毛,后面繼續探索。