• 盘一盘 Thread源码


    线程是操作系统能够进行运算调度的最小单位。它被包含在进程之中,是进程中的实际运作单位。一条线程指的是进程中一个单一顺序的控制流,一个进程中可以并发多个线程,每条线程并行执行不同的任务。

    继承关系图

    线程的创建方式有很多种。常用的有:继承Thread(),重写该类的run()方法;实现Runnable接口,并重写该接口的run()方法。

    其实Thread类本身也是实现了Runnable接口,而run()方法最先是在Runnable接口中定义的方法。

    主要属性

    //  线程的名称
    private volatile char  name[];
    
    //  线程的优先级
    private int            priority;
    
    //  是否是单步执行
    private boolean     single_step;
    
    //  是否是守护线程
    private boolean     daemon = false;
    
    //  JVM虚拟机的状态
    private boolean     stillborn = false;
    
    //  将会被执行的 Runnable
    private Runnable target;
    
    //  当前线程的组
    private ThreadGroup group;
    
    // 当前线程的上下文
    private ClassLoader contextClassLoader;
    
    // 当前线程继承的访问控制权限
    private AccessControlContext inheritedAccessControlContext;
    
    // 默认线程的自动编号
    private static int threadInitNumber;
    // 得到下个thread ID
    private static synchronized int nextThreadNum() {
         return threadInitNumber++;
    }
    
    // 与当前线程有关的ThreadLocal值
    ThreadLocal.ThreadLocalMap threadLocals = null;
    
    //  与当前线程相关的InheritableThreadLocal值。
    ThreadLocal.ThreadLocalMap inheritableThreadLocals = null;
    
    
    //  该线程请求的堆栈大小 默认一般为空 JVM自行分配
    private long stackSize;
    
    
    //  当前线程终止后,JVM的私有状态
    private long nativeParkEventPointer;
    
    // 当前线程的专属ID
    private long tid;
    
    //  用来生成 thread ID
    private static long threadSeqNumber;
    
    //  线程状态,0代表线程未启动 Runable
    private volatile int threadStatus = 0;
    
    // 中断阻塞器:当线程发生IO中断时,需要在线程被设置为中断状态后调用该对象的interrupt方法
    volatile Object parkBlocker;
    
    
    // 阻塞器锁,主要用于线程中断
    private volatile Interruptible blocker;
    private final Object blockerLock = new Object();
    
    // 阻断锁
    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;

    构造方法

    我们平时惯用new Thread()方法去创建一个线程,实际上线程初始化的过程中已经完成了很多默认的配置
    //  init方法相关参数
    //  g          线程组
    //  target     实现 Runnable接口类对象,就是调用 run方法的目标对象
    // name       线程名称
    // stackSize  栈的大小 该值对JVM而言只是一个建议,JVM会动态选择更合适的值
    // acc        访问控制权限
    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();
    
        // 获取系统的security
        SecurityManager security = System.getSecurityManager();
    
        // 没有指定线程组的话,创建的所有线程属于相同的线程组。
        if (g == null) {
            // 先将secuity的线程组赋给新线程的线程组
            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();
        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);
       
        // 分配线程栈的大小
        this.stackSize = stackSize;
    
        // 分配线程Id ThreadID是由JVM分配的,并不是系统的真正线程ID
        tid = nextThreadID();
    }
    
    private void init(ThreadGroup g, Runnable target, String name, long stackSize) {
        init(g, target, name, stackSize, null);
    }
    
    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(ThreadGroup group, Runnable target) {
        init(group, target, "Thread-" + nextThreadNum(), 0);
    }
    
    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) {
        init(group, target, name, 0);
    }
    
    public Thread(ThreadGroup group, Runnable target, String name,
                  long stackSize) {
        init(group, target, name, stackSize);
    }

    native方法

    // 获得当前线程
    public static native Thread currentThread();
    
    // 使当前线程从 运行状态Running 变为 就绪状态 Runnable
    public static native void yield();
    
    // 使当前线程进入休眠状态
    public static native void sleep(long millis) throws InterruptedException;
    
    // 使线程进入就绪状态 Runnable
    private native void start0();
    
    // 判断线程是否为中断状态
    private native boolean isInterrupted(boolean ClearInterrupted);
    
    // 判断线程是否存活
    public final native boolean isAlive();
    
    // 获取所有线程列表
    private native static StackTraceElement[][] dumpThreads(Thread[] threads);
    private native static Thread[] getThreads();
    
    // 设置线程优先等级
    private native void setPriority0(int newPriority);  
    
    // 停止线程 该方法已被弃用
    private native void stop0(Object o);
    
    // 线程暂停
    private native void suspend0();
    
    // 线程继续执行
    private native void resume0();
    
    // 线程中断
    private native void interrupt0();
    
    // 设置线程名
    private native void setNativeName(String name);

    这里不得不说和线程相关的几个Object Native方法。

    // 随机唤醒在此对象监视器(锁)上等待的单个线程。
    public final native void notify();
    
    //  唤醒所有等待在该对象上的线程。
    public final native void notifyAll();
    
    //  导致当前的线程等待,直到其他线程调用此对象的 notify() 方法或 notifyAll() 方法
    public final void wait() throws InterruptedException {
        wait(0);
    }
    
    // 超时等待一段时间,这里的参数是毫秒,也就是等待长达n毫秒,如果没有通知就超时返回。
    public final native void wait(long timeout) throws InterruptedException;
    我最开始有些疑惑,为什么wait(),notify(),notifyAll()用来操作线程会定义在Object类中?
    不妨我们先做一个假设:将wait、notify和线程队列都放到Thread中,那么在wait、notify的调度过程中必然要求某个Thread知道其他所有Thread的信息,显然是不合理的。
    而放到对象中,让对象维护所有竞争锁线程的队列,各个线程无必然联系。
     

    关键方法

    start() 启动线程

    public synchronized void start() {
            // 判断线程状态是否启动,不允许同一线程启动2次!
        if (threadStatus != 0)
            throw new IllegalThreadStateException();
    
        // 向线程组中添加当前线程
        group.add(this);
    
        // 使线程进入就绪状态 Runnable
        boolean started = false;
        try {
            start0();
            started = true;
        } finally {
            try {
                // 若线程启动失败,则通知该线程组,回滚线程组状态
                // 该线程被视为线程组的未启动成员,并允许后续尝试启动该线程。
                if (!started) {
                    group.threadStartFailed(this);
                }
            } catch (Throwable ignore) {
                /* do nothing. If start0 threw a Throwable then
                  it will be passed up the call stack */
            }
        }
    }

    checkAccess() 检查当前线程是否有修改权限,该方法在线程状态变更前多次被调用

    public final void checkAccess() {
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            // 通过Java安全管理器检查当前线程是否有修改权限
            security.checkAccess(this);
        }
    }

    run()  使线程从就绪状态 Runnable转化为运行状态 Running   -todo线程启动过程中由start到run的过程非常复杂。

    public void run() {
        // 调用 run方法的目标对象
        if (target != null) {
            target.run();
        }
    }

    exit()  该方法 run方法执行完成后调用,在线程结束退出之前进行清理工作。

    private void exit() {
        // 释放资源
        if (group != null) {
            group.threadTerminated(this);
            group = null;
        }
        
        target = null;
        
        threadLocals = null;
        inheritableThreadLocals = null;
        inheritedAccessControlContext = null;
        blocker = null;
        uncaughtExceptionHandler = null;
    }
    stop() stop方法是不安全的,它会立即停止线程执行,线程的后续执行不连贯。可能会导致一些清理性的工作的得不到完成,如文件,数据库等的关闭。故被标记为@Deprecated
    @Deprecated
    public final void stop() {
        SecurityManager security = System.getSecurityManager();
        if (security != null) {
            checkAccess();
            if (this != Thread.currentThread()) {
                security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);
            }
        }
     
        if (threadStatus != 0) {
            resume(); // Wake up thread if it was suspended; no-op otherwise
        }
     
        stop0(new ThreadDeath());
    }

    interrupt()  中断线程

    public void interrupt() {
        if (this != Thread.currentThread())
            checkAccess();
    
    
        synchronized (blockerLock) {
            Interruptible b = blocker;
            if (b != null) {
                interrupt0();           // Just to set the interrupt flag
                b.interrupt(this);
                return;
            }
        }
        interrupt0();
    }
    setPriority()、getPriority()  设置、获取线程优先级
    public final void setPriority(int newPriority) {
        ThreadGroup g;
        checkAccess();
        // 线程优先级范围仅分 1~10 级
        if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {
            throw new IllegalArgumentException();
        }
        if((g = getThreadGroup()) != null) {
            if (newPriority > g.getMaxPriority()) {
                newPriority = g.getMaxPriority();
            }
            setPriority0(priority = newPriority);
        }
    }
    
    public final int getPriority() {
        return priority;
    }
     
    join()  在当前线程中调用另一个线程的join()方法,使当前线程转入阻塞状态,直到另一个进程运行结束,当前线程再由阻塞转为就绪状态。
    public final void join() throws InterruptedException {
        join(0);
    }
    
    public final synchronized void join(long millis) throws InterruptedException {
        long base = System.currentTimeMillis();
        long now = 0;
    
    
        if (millis < 0) {
            throw new IllegalArgumentException("timeout value is negative");
        }
    
    
        if (millis == 0) {
            while (isAlive()) {
                wait(0);
            }
        } else {
            while (isAlive()) {
                long delay = millis - now;
                if (delay <= 0) {
                    break;
                }
                wait(delay);
                now = System.currentTimeMillis() - base;
            }
        }
    }

    setDaemon() 将该线程标记为守护线程或用户线程。当正在运行的线程都是守护线程时,Java 虚拟机退出。

    public final void setDaemon(boolean on) {
        checkAccess();
        // 该方法必须在启动线程前调用
        if (isAlive()) {
            throw new IllegalThreadStateException();
        }
        daemon = on;
    }
  • 相关阅读:
    获得 Web Service 方法的描述信息
    make menuconfig 报错
    汇编调用c函数为什么要设置栈
    UBoot Makefile文件分析
    UBoot启动过程完全分析(转)
    (转)在fedora12下用crosstoolng建立armlinux交叉编译环境
    UBoot编译过程完全分析(转)
    雷军:给互联网创业者的“七字”建议
    uboot根目录下makefile
    Redhat 5 配置Samba服务器
  • 原文地址:https://www.cnblogs.com/LemonFive/p/11219356.html
Copyright © 2020-2023  润新知