Thread类学习(一)
Thread類API中的英文描述:
file:///D:/Java/JDK8/Docs/docs/api/index.html
英語不好,大致的意思是:
線程是程序執行時的線程,java虛擬機(JVM)允許一個應用運行多個線程(并發)。
每一個線程都自己的優先權,優先級高的線程會比優先級低的線程優先執行。每一個線程可以被設置成守護線程(daemon),當一段代碼運行一些線程時,會創建一個Thread類的對象,這個新的線程初始的優先級是創建這個線程對象時程序員設定好的,僅且僅當用戶把這個線程設定成daemon,這個線程才是daemon
當java虛擬機(JVM)開啟時,這兒通常有一個非daemon線程(一般的會調用某個類的main方法),java虛擬機(JVM)會一直執行這些線程,直到出現下面幾種情況:
第一種:程序調用Runtime類的退出方法,并且安全管理器允許該退出操作
第二種:除了daemon線程外的其他所有線程執行完畢(處于dead狀態);線程run方法中遇到return語句;線程拋出一個run方法無法處理的異常
有兩種方法來創建一個新的線程。
第一種:聲明一個類,該類繼承Thread,該類應該重寫Thread類的run方法,通過調用start方法來啟動該線程,下面給出一個列子:
1 class PrimeThread extends Thread { 2 long minPrime; 3 PrimeThread(long minPrime) { 4 this.minPrime = minPrime; 5 } 6 7 public void run() { 8 // compute primes larger than minPrime 9 . . . 10 } 11 }?
第二種:聲明一個類,實現Runnable接口,重寫Runnable接口中的run方法,下面也給出一個例子:
1 class PrimeRun implements Runnable { 2 long minPrime; 3 PrimeRun(long minPrime) { 4 this.minPrime = minPrime; 5 } 6 public void run() { 7 // compute primes larger than minPrime 8 . . . 9 } 10 }下面我們來看一下Thread的源代碼部分:
1. Thread類實現了Runnable接口:
public class Thread implements Runnable2. Thread類的構造器:
1 public Thread() 2 public Thread(Runnable target) 3 Thread(Runnable target, AccessControlContext acc) 4 public Thread(ThreadGroup group, Runnable target) 5 public Thread(String name) 6 public Thread(ThreadGroup group, String name) 7 public Thread(Runnable target, String name) 8 public Thread(ThreadGroup group, Runnable target, String name) 9 public Thread(ThreadGroup group, Runnable target, String name, long stackSize)Thread類一共有9個構造器。其中第3個構造器沒有public修飾,默認用default修飾,同一個包下可用,不多做說明。
通過上面9個構造器(除3)可以看出,用戶在創建一個Thread類的對象時,可以設定的參數有:ThreadGroup、Runnable、name、stackSize
ThreadGroup:是java.lang包下的一個ThreadGroup類,ThreadGroup對象表示一個線程的集合,也可以包含另一個ThreadGroup對象。
Thread類init方法關于ThreadGroup部分源碼:
1 Thread parent = currentThread(); 2 SecurityManager security = System.getSecurityManager(); 3 if (g == null) { 4 /* Determine if it's an applet or not */ 5 6 /* If there is a security manager, ask the security 7 manager what to do. */ 8 if (security != null) { 9 g = security.getThreadGroup(); 10 } 11 12 /* If the security doesn't have a strong opinion of the 13 matter use the parent thread group. */ 14 if (g == null) { 15 g = parent.getThreadGroup(); 16 } 17 } 18 19 /* checkAccess regardless of whether or not threadgroup 20 is explicitly passed in. */ 21 g.checkAccess();其中currentThread()方法是獲取當前運行的線程,下面寫段代碼做個試驗:
1 public class Demo7{ 2 public static void main(String[] args){ 3 Thread t = Thread.currentThread(); 4 System.out.println(t.getName()); 5 } 6 }System.getSecurityManager()是System類中的一個靜態方法,該方法是用來返回一個SecurityManager類的對象security,下面是System類中getSecurityManager():
/*** Gets the system security interface.** @return if a security manager has already been established for the* current application, then that security manager is returned;* otherwise, <code>null</code> is returned.* @see #setSecurityManager*/public static SecurityManager getSecurityManager() {return security;}注釋說明,如果這個安全管理已經創建security對象,則返回這個security,如果沒有,則返回null,其中System類的security初始值被設置為null。
/* The security manager for the system.*/private static volatile SecurityManager security = null;再看Thread類中init方法關于ThreadGroup部分做了什么處理?
先創建兩個對象parent和security:
Thread parent = currentThread(); SecurityManager security = System.getSecurityManager();接著對用戶創建Thread類對象設置的參數做一個判斷,如果用戶沒有設定ThreadGroup參數,則傳遞一個null值
init方法先判斷這個參數是否為null,如果不為null,則判斷security是否為空,如果不為空,則獲取security所在的ThreadGroup賦值給用戶創建的Thread對象,即g的值
接著再判斷g是否為空,如果還為null,則將當前線程的ThreadGroup賦值給g。總之,如果用戶未設置g值,就把security的g值賦值給g,如果security的g值也為空,就把parent的g值賦給g。
最后再調用g(ThreadGroup)的checkAccess方法,ThreadGroup類的checkAccess方法源碼:
1 public final void checkAccess() { 2 SecurityManager security = System.getSecurityManager(); 3 if (security != null) { 4 security.checkAccess(this); 5 } 6 }可以看出該方法,其實是調用了SecurityManager對象的checkAccess(ThreadGroup g)方法:
1 public void checkAccess(ThreadGroup g) { 2 if (g == null) { 3 throw new NullPointerException("thread group can't be null"); 4 } 5 if (g == rootGroup) { 6 checkPermission(SecurityConstants.MODIFY_THREADGROUP_PERMISSION); 7 } else { 8 // just return 9 } 10 }其中rootGroup應該是g的最高級parent(未必正確),看一下源碼:
1 private static ThreadGroup rootGroup = getRootGroup(); 2 private static ThreadGroup getRootGroup() { 3 ThreadGroup root = Thread.currentThread().getThreadGroup(); 4 while (root.getParent() != null) { 5 root = root.getParent(); 6 } 7 return root; 8 }checkPermission(SecurityConstants.MODIFY_THREADGROUP_PERMISSION)這個坑之后再填吧,挖不下去了。
Runnable:前面介紹了創建Thread類對象的兩種方法,其中一種就是傳入一個Runnable對象。
如果在創建一個線程時,沒有傳入Runnable對象,則init方法默認傳入的是一個null值,來看一下源碼:
public Thread() {init(null, null, "Thread-" + nextThreadNum(), 0); }?
在看看init方法對應參數代表什么意思:
private void init(ThreadGroup g, Runnable target, String name, long stackSize) {init(g, target, name, stackSize, null, true); }?
從中還可以看出,如果在創建Thread類對象時,沒有指定其姓名,會默認設置名字,即Thread-加上nextThreadNum()返回值:
private static int threadInitNumber; private static synchronized int nextThreadNum() {return threadInitNumber++; }?
所以第一個線程的名字會默認為Thread-0,第二個線程的名字為Thread-1......
stackSize:棧的大小,待補充......
3. 線程的狀態
Thread類有個內部枚舉類State,該類就聲明了線程的幾種狀態:
public enum State {NEW,RUNNABLE,BLOCKED,WAITING,TIMED_WAITING,TERMINATED; }?
NEW:線程剛創建時具有的狀態;
public class Demo8{public static void main(String[] args){Thread t = new Thread();System.out.println(t.getState());} }?
RUNNABLE:是指線程正在運行,線程獲取CPU的時間片
public class Demo8{public static void main(String[] args){Thread t = new Thread();t.start();System.out.println(t.getState());} }?
BLOCKED:是指程序進入阻塞狀態,假如有兩個線程,并且兩個線程都是同步安全的(synchronized),當一個線程處于runnable狀態時,則另一個線程處于blocked狀態。
public class Demo8{public static void main(String[] args){Thread t1= new Thread(){public void run(){synchronized(Thread.class){for(int i = 0; i < 100; i++){}}}};Thread t2 = new Thread(){public void run(){synchronized(Thread.class){System.out.println(t1.getState());}}};t1.setPriority(1);t2.setPriority(10);t1.start();t2.start();} }?
WAITING:程序處于等待狀態,調用wait()、join()、await()、lock()等方法,都會使線程處于waiting狀態,需要注意的是這些方法必須是無參數的。
public class Demo8{public static void main(String[] args){Thread t1 = new Thread(){public void run(){try{join(); }catch(InterruptedException e){e.printStackTrace();}}};Thread t2 = new Thread(){public void run(){System.out.println(t1.getState());}};t1.start();t2.start();} }?
TIMED_WAITING:程序處于限時等待狀態,調用wait()、join()、await()、lock()、sleep()等方法,都會使線程處于waiting狀態,需要注意的是這些方法必須加入參數。
TERMINATED:終止狀態,即線程結束
4. Thread類中部分方法源碼解析
————this.start()方法
public synchronized void start() {if (threadStatus != 0)throw new IllegalThreadStateException();group.add(this);boolean started = false;try {start0();started = true;} finally {try {if (!started) {group.threadStartFailed(this);}} catch (Throwable ignore) {}} }?
可以看出線程是在調用start方法時加入init方法中指定的線程池的,其次線程在創建時并不是把內部的枚舉類State的NEW值給這個線程,而是定義一個int型的threadStatus
變量,并且這個變量初始值為0。
private volatile int threadStatus = 0;?
并且start還調用了一個本地的start0()方法,由于沒看過JVM相關的知識,所以對于native修飾的方法無能無力:
private native void start0();?
不過IBM有一篇文章對此講解的比較詳細,這里附上鏈接:https://www.ibm.com/developerworks/cn/java/j-lo-processthread/#icomments
大概的意思是java的start方法會調用?JVM_StartThread方法,而?JVM_StartThread方法會創建一個與本地相關的線程,該線程與java創建的線程有著一一對應關系。
JVM_ENTRY(void, JVM_StartThread(JNIEnv* env, jobject jthread)) …native_thread = new JavaThread(&thread_entry, sz); …?
這篇文章并沒有詳細講解JVM的代碼實現過程,而是給出了方法調用圖,該圖來自上面鏈接的那篇文章:
————setPriority(int)方法
這里先留坑,簡單講一下,線程的優先級可以理解為線程搶占cpu時間片的概率,因此并不能保證優先級高一定會先執行
1 public class Demo2 { 2 public static void main(String[] args) { 3 Thread t1 = new Thread() { 4 @Override 5 public void run() { 6 for(int i = 0; i < 1000; i++) { 7 System.out.println("********"); 8 } 9 } 10 }; 11 Thread t2 = new Thread() { 12 @Override 13 public void run() { 14 for(int i = 0; i < 1000; i++) { 15 System.out.println("--------"); 16 } 17 } 18 }; 19 t1.setPriority(1); 20 t2.setPriority(10); 21 t1.start(); 22 t2.start(); 23 } 24 }?
其次,windows操作系統的優先級為7個級別(未驗證),而java的優先級分為10個級別,所以java程序1~10幾個優先級中,必定有幾個優先級在windows操作系統下級別是一樣的,真正決定優先級的應該是本地的setPriority0()方法。
setPriority0(priority = newPriority);?
—————activeCount方法,獲取當前線程池中的線程數量
1 import java.lang.reflect.InvocationTargetException; 2 import java.lang.reflect.Method; 3 public class Demo3 { 4 public static void main(String[] args) throws NoSuchMethodException, SecurityException, IllegalAccessException, IllegalArgumentException, InvocationTargetException { 5 MyRunnable m = new MyRunnable(); 6 Thread t1 = Thread.currentThread(); 7 ThreadGroup tg = t1.getThreadGroup(); 8 Thread t2 = new Thread(m); 9 Class c = ThreadGroup.class; 10 Method declaredMethod = c.getDeclaredMethod("add", Thread.class); 11 Method method = declaredMethod; 12 method.setAccessible(true); 13 method.invoke(tg,t2); 14 System.out.println(Thread.activeCount()); 15 System.out.println(t1.getName()); 16 System.out.println(tg.getName()); 17 } 18 } 19 class MyRunnable implements Runnable{ 20 public void run() {} 21 }這里是利用反射的機制,調用ThreadGroup類中的add(Thread t)方法,把線程添加到指定的線程池,這里要說明的是,創建的線程對象時,Thread類構造器調用的init初始化方法,并沒有把線程加入指定的線程池,而是在start方法中調用了ThreadGroup的add方法。
未完待續......
?
轉載于:https://www.cnblogs.com/kirito2924/p/9147630.html
總結
以上是生活随笔為你收集整理的Thread类学习(一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Arduino IDE 配置文件
- 下一篇: matlab反拉氏变换,matlab拉普