Java Thread多线程源码剖析

Thread多线程源码剖析

源码剖析

package java.lang;

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.WeakReference;
import java.security.AccessController;
import java.security.AccessControlContext;
import java.security.PrivilegedAction;
import java.util.Map;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.locks.LockSupport;
import sun.nio.ch.Interruptible;
import sun.reflect.CallerSensitive;
import sun.reflect.Reflection;
import sun.security.util.SecurityConstants;

/**
  * 线程就是程序中一个线程的执行.JVM允许一个应用中多个线程并发执行.
  *
  * 每个线程都有优先级.高优先级线程优先于低优先级线程执行.
  * 每个线程都可以(不可以)被标记为守护线程.
  * 当线程中的run()方法代码里面又创建了一个新的线程对象时,新创建的线程优先级和父线程优先级一样.
  * 当且仅当父线程为守护线程时,新创建的线程才会是守护线程.
  *
  * 当JVM启动时,通常会有唯一的一个非守护线程(这一线程用于调用指定类的main()方法)
  * JVM会持续执行线程直到下面情况某一个发生为止:
  * 1.类运行时exit()方法被调用 且 安全机制允许此exit()方法的调用.
  * 2.所有非守护类型的线程均已经终止,or run()方法调用返回 or 在run()方法外部抛出了一些可传播性的异常.
  *
  *
  * 有2种方式可以创建一个可执行线程.
  * 1.定义一个继承Thread类的子类.子类可覆写父类的run()方法.子类实例分配内存后可运行(非立即,取决于CPU调用)
  * 比如:计算大于指定值的素数的线程可以写成如下
  * class PrimeThread extends Thread {
  * long minPrime;
  * PrimeThread(long minPrime) {
  * this.minPrime = minPrime;
  * }
  *
  * public void run() {
  * // compute primes larger than minPrime
  * . . .
  * }
  * }
  * 下面的代码将创建一个线程并启动它.
  * PrimeThread p = new PrimeThread(143);
  * p.start();
  *
  * 2.另一个实现线程的方式就是使类实现Runnable接口.
  * 此类自己会实现run()方法.然后此线程会被分配内存,当线程被创建时,会传入一个参数,然后开始执行.
  * 此种方式的样例代码如下:
  *
  * class PrimeRun implements Runnable {
  * long minPrime;
  * PrimeRun(long minPrime) {
  * this.minPrime = minPrime;
  * }
  *
  * public void run() {
  * // compute primes larger than minPrime
  * . . .
  * }
  * }
  * 下面的代码能够创建一个线程并开始执行:
  * PrimeRun p = new PrimeRun(143);
  * new Thread(p).start();
  *
  * 每一个线程都有一个用于目的标识的名字.多个线程可以有相同的名字.
  * 线程被创建时如果名字没有被指定,则系统为其自动生成一个新的名字.
  *
  * 除非特别说明,否则在创建线程时传入一个null参数到构造器或者方法会抛出空指针异常NullPointerException
  *
  * @author unascribed
  * @see Runnable
  * @see Runtime#exit(int)
  * @see #run()
  * @see #stop()
  * @since JDK1.0
  */
  
public class Thread implements Runnable {

  //确保本地注册(类构造器方法方法用于类初始化)是创建一个线程首要做的事情.

  private static native void registerNatives();//注册的都是一些本地方法
  static {

      registerNatives();
  }
  
  private volatile String name;       //线程名:可更改且线程可见
    private int            priority;    //线程优先级,用int表示,有10级,初始为5
    private Thread         threadQ;     //未知
    private long           eetop;       //JVM中的JavaThread指针
    
    //是否单步执行此线程
  private boolean single_step;
  //此线程是否为守护线程
  private boolean     daemon = false;
  //虚拟机(JVM)状态
  private boolean     stillborn = false;
  //用来引用构造函数中传递的Runnable参数,run()方法执行的目标代码
  private Runnable target;
  //线程所属的组
  private ThreadGroup group;
  //线程用的上下文类加载器,该上下文类加载器可供线程加载类和资源
  private ClassLoader contextClassLoader;
  //此线程继承的访问(请求)控制上下文
  private AccessControlContext inheritedAccessControlContext;
  //计数变量,用在nextThreadNum方法中为匿名线程生成名称
  private static int threadInitNumber;
  //静态加锁的自增threadInitNumber变量方法,每调用一次,变量加一
  private static synchronized int nextThreadNum() {
        return threadInitNumber++;
    }
    
    //此线程的本地变量值.此map由ThreadLocal类进行维护,因为这个类在ThreadLocal中是包级私有的.
    //ThreadLocalMap是一个用于维护线程本地变量的hashmap,此hashmap的key引用类型为弱引用,这是为了支持大且长期存活的使用方法.
    ThreadLocal.ThreadLocalMap threadLocals = null;
    //和此线程相关的由继承得到的本地变量值.此hashmap由InheritableThreadLocal类进行维护.
    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
    //此线程请求栈的深度,如果线程创建者未指定栈深度则其值为0.
    //此数字如何被使用完全取决于虚拟机自己;也有一些虚拟机会忽略此变量值.
    private long stackSize;
    //此变量表示:在本地线程终止后,JVM私有的一个状态值
    private long nativeParkEventPointer;
    //线程的ID
    private long tid;
    //用于生成线程ID
    private static long threadSeqNumber;
    //为工具提供的线程状态值,初始化值表示当前线程还未运行
    private volatile int threadStatus = 0;
    //私有同步方法,获取下一个线程id
    private static synchronized long nextThreadID() {
        return ++threadSeqNumber;
    }
    
    /**
  * 此变量为用于调用java.util.concurrent.locks.LockSupport.park方法的参数.
  * 其值由方法(private) java.util.concurrent.locks.LockSupport.setBlocker进行设定.
  * 其值访问由方法java.util.concurrent.locks.LockSupport.getBlocker进行获取.
  */
    volatile Object parkBlocker;
    /*
  * 在可中断I/O操作中,本线程中的此对象会被阻塞.
  * 如果此线程的中断状态位被设置,则应该调用此阻塞对象的中断(interrupt)方法.
  */
    private volatile Interruptible blocker;
    //设置上述blocker变量时用的锁
    private final Object blockerLock = new Object();
    
    //设定block变量的值;通过java.nio代码中的 sun.misc.SharedSecrets进行调用.
    void blockedOn(Interruptible b) {
        synchronized (blockerLock) {
            blocker = b;
        }
    }
    
    //一个线程可以拥有的最低优先级
  public final static int MIN_PRIORITY = 1;
  //线程的默认优先级
  public final static int NORM_PRIORITY = 5;
  //一个线程可以拥有的最高优先级.
  public final static int MAX_PRIORITY = 10;
    
    //返回当前正在执行线程对象的引用,需注意这是一个本地方法
    public static native Thread currentThread();
    
    /**
  * 提示线程调度器当前线程愿意放弃当前CPU的使用。当然调度器可以忽略这个提示。
  *
  * 让出CPU是一种启发式的尝试,以改善线程之间的相对进展,否则将过度利用CPU。
  * 它的使用应该与详细的分析和基准测试相结合以确保它实际上具有预期的效果。
  *
  * 此方法很少有适用的场景.它可以用于debug或者test,通过跟踪条件可以重现bug.
  * 当设计并发控制结构(如java.util.concurrent.locks包中的并发结构)时,它可能比较有用.
  */
    public static native void yield();
    
    /**
  * 此方法会引起当前执行线程sleep(临时停止执行)指定毫秒数.
  * 此方法的调用不会引起当前线程放弃任何监听器(monitor)的所有权(ownership).
  * 让出资源但是并不会释放对象锁。
  */
    public static native void sleep(long millis) throws InterruptedException;
    //millis为毫秒,nanos为纳秒,1000纳秒=1毫秒,其他跟sleep方法一样
    public static void sleep(long millis, int nanos)
    throws InterruptedException {
        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }
        if (nanos < 0 || nanos > 999999) {
            throw new IllegalArgumentException(
                                "nanosecond timeout value out of range");
        }
        if (nanos >= 500000 || (nanos != 0 && millis == 0)) {
            millis++;
        }
        sleep(millis);
    }
    
    //初始化一个新线程的方法
    //g所属的线程组、target待执行的目标代码、name新线程的名字、stackSize用于新线程分配所需堆栈大小
    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize) {
        init(g, target, name, stackSize, null, true);
    }
    //重载初始化方法
    //前四个参数同上
    //AccessControlContext 用于继承的访问控制上下文
    //inheritThreadLocals 如果值为true,从构造线程获取可继承的线程局部变量的初始值
    private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals) {
        //如果name为空,则抛空异常。
        if (name == null) {
            throw new NullPointerException("name cannot be null");
        }
        //name不为空,则将值赋给线程私有name变量
        this.name = name;
        //将调用该初始化方法的线程,设为待创建线程的父线程
        Thread parent = currentThread();
        //获取系统的安全管理工具
        SecurityManager security = System.getSecurityManager();
        //如果线程组为空
        if (g == null) {
            //首先检测其是否为一个小应用
            
            //如果有安全管理,查询安全管理需要做的工作
            if (security != null) {
                g = security.getThreadGroup();
            }
            
            //如果安全管理在线程所属父线程组的问题上没有什么强制的要求
            //线程组将使用父线程的线程组
            if (g == null) {
                g = parent.getThreadGroup();
            }
        }

        //无论所属线程组是否显示传入,都要进行检查访问.
        //检查是否允许调用线程修改线程组参数
        g.checkAccess();

        //检查是否有访问权限
        if (security != null) {
            //该函数的定义在下面,证明创建当前子类实例能够忽略安全限制
            if (isCCLOverridden(getClass())) {
                security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
            }
        }
        
        //线程组中的计数方法,
        //无论线程启动与否都需计数,以免破坏其中包含未启动线程的守护进程线程组。
        g.addUnstarted();
        //线程私有变量赋值
        this.group = g;
        this.daemon = parent.isDaemon(); //如果父线程为守护线程,则此线程也被 设置为守护线程.
        this.priority = parent.getPriority(); //当前线程继承父线程的优先级
        //如果安全管理为空,或者父线程能够忽略安全限制调用父线程的getContextClassLoader,通过反射方式获取上下文类加载器
        //否则直接获取父线程的类加载器
        if (security == null || isCCLOverridden(parent.getClass()))
            //如果安全管理器存在,且父线程的类加载器不为null,且它们不相同,且也不是父子关系,则此方法的调用会导致安全管理的方法 checkPermission的调用,用于确定对上下文类加载器的检索是否被允许.
            this.contextClassLoader = parent.getContextClassLoader();
        else
            this.contextClassLoader = parent.contextClassLoader;
            //如果父线程的访问控制上下文不为空,则将访问控制上下文直接赋值给此线程的访问控制上下文,否则通过访问控制器获取上下文
        this.inheritedAccessControlContext =
                acc != null ? acc : AccessController.getContext();
        
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值