一文看盡Java-Thread

  • 2019 年 10 月 3 日
  • 筆記

一、前言

     主要分成兩部說起:Thread源碼解讀和常見面試題解答,廢話不多說開始;

二、源碼解讀

     首先看下構造函數,構造函數都是通過調用init方法對屬性進行初始化,主要是對執行緒組、執行緒名字、棧大小等資訊進行初始化;init內部通過調用currentThread本地方法,獲取當前的執行緒,這個本地方法封裝在JVM中,有興趣的可以看下這個這個鏈接查找下JVM實現https://hg.openjdk.java.net/jdk8u,接下來對ThreadGroup的判斷,如果沒有傳入執行緒組的話, 第一是使用SecurityManager中的ThreadGroup, 如果從SecurityManager 中獲取不到ThreadGroup(), 那麼就從當前執行緒中獲取執行緒組,最後做了檢驗和些參數的賦值,整體上相對比較簡單;

    private void init(ThreadGroup g, Runnable target, String name,                      long stackSize) {        init(g, target, name, stackSize, null);    }    private void init(ThreadGroup g, Runnable target, String name,                      long stackSize, AccessControlContext acc) {        if (name == null) {            throw new NullPointerException("name cannot be null");        }        this.name = name.toCharArray();        Thread parent = currentThread();        SecurityManager security = System.getSecurityManager();        if (g == null) {            /* Determine if it's an applet or not */            /* If there is a security manager, ask the security manager               what to do. */            if (security != null) {                g = security.getThreadGroup();            }            /* If the security doesn't have a strong opinion of the matter               use the parent thread group. */            if (g == null) {                g = parent.getThreadGroup();            }        }        /* checkAccess regardless of whether or not threadgroup is           explicitly passed in. */        g.checkAccess();        /*         * Do we have the required permissions?         */        if (security != null) {            if (isCCLOverridden(getClass())) {                security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);            }        }        g.addUnstarted();        this.group = g;        this.daemon = parent.isDaemon();        this.priority = parent.getPriority();        if (security == null || isCCLOverridden(parent.getClass()))            this.contextClassLoader = parent.getContextClassLoader();        else            this.contextClassLoader = parent.contextClassLoader;        this.inheritedAccessControlContext =                acc != null ? acc : AccessController.getContext();        this.target = target;        setPriority(priority);        if (parent.inheritableThreadLocals != null)            this.inheritableThreadLocals =                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);        /* Stash the specified stack size in case the VM cares */        this.stackSize = stackSize;        /* Set thread ID */        tid = nextThreadID();    }    public Thread() {        init(null, null, "Thread-" + nextThreadNum(), 0);    }      public Thread(Runnable target) {        init(null, target, "Thread-" + nextThreadNum(), 0);    }    Thread(Runnable target, AccessControlContext acc) {        init(null, target, "Thread-" + nextThreadNum(), 0, acc);    }   // 執行緒名    public Thread(String name) {        init(null, null, name, 0);    }    //執行緒組和執行緒名    public Thread(ThreadGroup group, String name) {        init(group, null, name, 0);    }    //執行緒任務,執行緒名    public Thread(Runnable target, String name){        init(null, target, name, 0);    }    // 執行緒組, 執行緒任務, 執行緒名 ,棧大小    public Thread(ThreadGroup group, Runnable target, String name, long stackSize) {        init(group, target, name, stackSize);    }

View Code

      接下來看下主要的屬性:

// 類載入的時候,調用本地的註冊本地方靜態方法, 這個方法是本地方法    private static native void registerNatives();    static {        registerNatives();    }    private volatile char  name[];    private int            priority;    private Thread         threadQ;    private long           eetop;    /* Whether or not to single_step this thread. */    private boolean     single_step;    /* Whether or not the thread is a daemon thread. */    // 設設置這個執行緒是否是守護執行緒    private boolean     daemon = false;    /* JVM state */    private boolean     stillborn = false;    /* What will be run. */    // 要執行的run方法的對象    private Runnable target;    /* The group of this thread */    // 這個執行緒的執行緒組    private ThreadGroup group;    /* The context ClassLoader for this thread */    // 這個執行緒的上下文類載入器    private ClassLoader contextClassLoader;    /* The inherited AccessControlContext of this thread */    private AccessControlContext inheritedAccessControlContext;    /* For autonumbering anonymous threads. */    private static int threadInitNumber;    private static synchronized int nextThreadNum() {        return threadInitNumber++;    }    /* ThreadLocal values pertaining to this thread. This map is maintained     * by the ThreadLocal class. */    ThreadLocal.ThreadLocalMap threadLocals = null;    /*     * InheritableThreadLocal values pertaining to this thread. This map is     * maintained by the InheritableThreadLocal class.     */    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;    /*     * The requested stack size for this thread, or 0 if the creator did     * not specify a stack size.  It is up to the VM to do whatever it     * likes with this number; some VMs will ignore it.     */     // 給這個執行緒設置的棧的大小,默認為0     private long stackSize;    /*     * JVM-private state that persists after native thread termination.     */    private long nativeParkEventPointer;    /*     * Thread ID     */       //執行緒id    private long tid;    /* For generating thread ID */    private static long threadSeqNumber;    /* Java thread status for tools,     * initialized to indicate thread 'not yet started'     */    private volatile int threadStatus = 0;    private static synchronized long nextThreadID() {        return ++threadSeqNumber;    }    /**     * The argument supplied to the current call to     * java.util.concurrent.locks.LockSupport.park.     * Set by (private) java.util.concurrent.locks.LockSupport.setBlocker     * Accessed using java.util.concurrent.locks.LockSupport.getBlocker     */    volatile Object parkBlocker;    /* The object in which this thread is blocked in an interruptible I/O     * operation, if any.  The blocker's interrupt method should be invoked     * after setting this thread's interrupt status.     */    private volatile Interruptible blocker;    private final Object blockerLock = new Object();    /* Set the blocker field; invoked via sun.misc.SharedSecrets from java.nio code     */    void blockedOn(Interruptible b) {        synchronized (blockerLock) {            blocker = b;        }    }    /**     * The minimum priority that a thread can have.     */     // 執行緒執行的最低優先順序 為1    public final static int MIN_PRIORITY = 1;   /**     * The default priority that is assigned to a thread.     */     // 執行緒默認的執行優先順序為 5    public final static int NORM_PRIORITY = 5;    /**     * The maximum priority that a thread can have.     */     // 執行緒執行的最高的優先順序為 10    public final static int MAX_PRIORITY = 10;

View Code

     最後介紹下方法的作用和執行緒狀態,源碼都比較簡單,沒必進行過多的介紹,都是通過調用JVM的本地方法實現;

     

    執行緒狀態:

   

、常見面試題

    1.執行緒與進程的區別?

       進程是資源分配最小的單位,執行緒是CPU調度最小的單位;

       執行緒屬於進程,共享進程分配的資源;

       進程屬於搶佔式調度,資源不相互共享;

    2.start和run的區別?

      run是Thread的一個普通的方法;

      start方法會創建一個新的子執行緒並啟動;

    3.sleep與wait的區別?

      sleep是Thread方法,wait是Object的方法;

      wait方法只能在synchroized方法或者塊中使用;

      Thread.sleep只會讓出CPU,不會改變鎖的行為;

      Object.wait不僅會讓出CPU,同時還會釋放佔有同步資源的鎖;

    4.執行緒狀態的轉化?

     圖中將WAITING 和TIMED_WAITING 兩個狀態合併為WAITING ,沒有分開,大家不要搞錯;

    

 

 

     5.如何處理執行緒的返回值?

        主執行緒等待法,使用while等待主執行緒返回值;

        join阻塞當前執行緒以等待子執行緒;

        通過FuTureTask獲取子執行緒的返回值;

public class MyCallable implements Callable<String> {      @Override      public String call() throws Exception {            String value="test";          System.out.println("start");          Thread.sleep(5000);          System.out.println("end");          return value;        }  }  public class FutureTaskDemo {        public static void main(String[] main) throws ExecutionException, InterruptedException {          FutureTask<String> futureTask=new FutureTask<String>(new MyCallable());            new Thread(futureTask).start();            if (!futureTask.isDone()){              System.out.println("waiting");          }          System.out.println("return"+futureTask.get());      }  }

View Code

        通過執行緒池獲取返回值; 

public class ThreadPoolDemo {      public static void main(String[] args){          ExecutorService executorService= Executors.newCachedThreadPool();          Future<String> futureTask=executorService.submit(new MyCallable());          if (!futureTask.isDone()){              System.out.println("wait");          }          try {              System.out.println(futureTask.get());          }catch (InterruptedException ex){              ex.printStackTrace();          }catch (ExecutionException ex){              ex.printStackTrace();          }finally {              executorService.shutdown();          }        }  }

View Code

    6.Thread和Runnable?

       Thread是類,Runnable是介面,Thread是Runnable實現;

       類的繼承單一原則,Runnable是更高層次的抽象;

 四、結束

  歡迎大家加群438836709!歡迎大家關注我!