1. 程式人生 > >一文看盡Java-Thread

一文看盡Java-Thread

一、前言

     主要分成兩部說起: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!歡迎大家關注我!

    &n