Thread源码解析

来源:互联网 发布:网络机顶盒怎么选 编辑:程序博客网 时间:2024/05/17 09:11

引言


在介绍Thread源码之前先简要介绍一下线程相关的一些基础知识。

线程定义

线程是现代操作系统调度的最小单元,一个进程可以创建多个线程来提高系统的吞吐量和执行效率。

:进程是操作系统资源分配和调度的基本单位,它可以创建多个线程,进程可创建的线程数量跟操作系统相关。

为什么要使用多线程?

  • 更多的处理器核心;
  • 更快的响应时间;
  • 更好的编程模型:java提供了一套完整的jmm规则,屏蔽了底层的一些操作,开发人员只需要关注自己的业务逻辑即可。

线程的状态

  • NEW:初始状态,线程被构建,还未调用start()方法;
  • RUNNABLE:运行状态,在java多线程模型中,就绪和运行都是运行状态;
  • BLOCKED:阻塞状态;
  • WAITING:等待状态,比如中断,需要其他的线程来唤醒;
  • TIME_WAITING:超时等待,可以在指定的时间内自行返回;
  • TERMINATED:终止状态,线程执行完毕。

Thread源码分析

  • 构造线程

构造函数:

//无参构造方法public Thread() {    init(null, null, "Thread-" + nextThreadNum(), 0);}//带参构造方法public Thread(Runnable target) {    init(null, target, "Thread-" + nextThreadNum(), 0);}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);}

所有的构造方法都调用了init这个方法,接下来我们就来详细的看看init方法到底是怎么来初始化线程的。

初始化线程:

private void init(ThreadGroup g, Runnable target, String name, long stackSize, AccessControlContext acc) {    //参数校验,线程name不能为null    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) {        //security不为null时,线程所在group为security的group        if (security != null) {            g = security.getThreadGroup();        }        //security为null时,直接使用父线程的group        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    tid = nextThreadID();}

  • 启动线程
public synchronized void start() {    //假若当前线程初始化还未做好,不能start,0->NEW状态    if (threadStatus != 0)        throw new IllegalThreadStateException();    //通知group该线程即将启动,group的未启动线程数量减1    group.add(this);    boolean started = false;    try {        start0();        started = true;    } finally {        try {            //启动不成功,group设置当前线程启动失败            if (!started) {                group.threadStartFailed(this);            }        } catch (Throwable ignore) {        }    }}

启动线程其实做了这么几件事:

  1. 检查线程是否初始化;
  2. 通知group,线程启动;
  3. 调用native方法start0()启动线程,启动后执行run()方法;
  4. 启动失败容错处理。

  • 线程中断
    中断可以理解为一个标识位的属性,它标识一个运行中的线程是否被其他线程进行了中断操作。

中断线程:

public void interrupt() {    //中断其他线程,需要先判断当前线程是否允许修改其他线程    if (this != Thread.currentThread())        checkAccess();    //中断该线程    synchronized (blockerLock) {        Interruptible b = blocker;        if (b != null) {            interrupt0();//设置中断标识位            b.interrupt(this);            return;        }    }    interrupt0();}

查看当前线程是否被中断:

public static boolean interrupted() {    return currentThread().isInterrupted(true);}

查看线程是否被中断,已中断返回false

public boolean isInterrupted() {    return isInterrupted(false);}

  • 线程的暂停、恢复和停止

: 这几个操作都加有@Deprecated注解,不推荐程序员使用

暂停:

//可能会造成死锁@Deprecatedpublic final void suspend() {    checkAccess();    suspend0();}

恢复:

//可能会造成死锁@Deprecatedpublic final void resume() {    checkAccess();    resume0();}

停止:

@Deprecatedpublic final synchronized void stop(Throwable obj) {    if (obj == null)        throw new NullPointerException();    SecurityManager security = System.getSecurityManager();    if (security != null) {        checkAccess();        if ((this != Thread.currentThread()) ||            (!(obj instanceof ThreadDeath))) {            security.checkPermission(SecurityConstants.STOP_THREAD_PERMISSION);        }    }    //线程还未初始化好,暂停该线程    if (threadStatus != 0) {        resume();     }    //jvm处理线程相关内容    stop0(obj);}

  • 线程优先级设置
public final void setPriority(int newPriority) {    ThreadGroup g;    checkAccess();    if (newPriority > MAX_PRIORITY || newPriority < MIN_PRIORITY) {        throw new IllegalArgumentException();    }    if((g = getThreadGroup()) != null) {        if (newPriority > g.getMaxPriority()) {            newPriority = g.getMaxPriority();        }        setPriority0(priority = newPriority);    }}

需要注意的是:线程优先级不能作为程序正确性的依赖,操作系统有线程优先级的设定,不以程序设定的优先级为准!


后记

到这里位置,Thread的源码分析基本上就结束了,创建线程当然还可以实现Runnable接口方式来完成。后续文章将会继续给出current包下相关源码分析。

0 0
原创粉丝点击