【并发】- 挖坑之二 Java Thread源码 线程是如何执行的

上节内容,在了解了进程、线程之后,我们开始写第一个多线程方法!
笔记来自以下课程:
http://concurrent.redspider.group/article/01/2.html
API简析_java.security.AccessControlContext类

学习多线程,那必然会了解线程是怎样执行的,怎样销毁的?如果线程任务很多,那需要一个对象把待执行的任务存起来,系统有空闲线程的时候去执行,那么引申出线程组是怎样执行任务的,有哪些问题我们在使用线程组的时候要注意。

了解一下计算机组成的知识,可以帮我们理解线程执行的一些操作(代码)。所以开篇第一问线程是如何初始化的

线程是如何初始化的?

创建和执行线程的方法就不在这里赘述了,网上很多。我们以最基本的new Thread(t).start()为例,一步步了解线程的执行过程。

首先,我们需要了解的是线程有哪些基本的属性,它们代表什么含义,在线程执行中起到了什么作用。为了进度,我们只研究主线,支线剧情和隐藏彩蛋请大家自行探索。

thread类主要方法&属性

name String 线程名
priority int 优先级
target Runnable 要执行的方法
threadLocals ThreadLocal.ThreadLocalMap 存储线程间共享的变量
group ThreadGroup 线程组
stackSize int 栈空间大小,可以手动指定线程占用的栈空大小
tid long 线程id(自增)

init 初始化方法
destory 销毁方法
start 启动线程方法

init 初始化方法

上一节说过,线程是进程开辟空间运行的函数,那在java创建线程也一样,需要知道当前线程的上下文。
为了更突出重点,这里我把精简过的源码放上来,原始代码放在后面。

private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals) {

        this.name = name;
		// 被初始化线程的父线程,就是当前线程
        Thread parent = currentThread();
        SecurityManager security = System.getSecurityManager();
        // 校验是否有修改线程组的权限
        g.checkAccess();

        // 校验是否具有继承/修改当前线程上下文的权限
		security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
		// 增加一个线程组中未启动线程的计数值
        g.addUnstarted();
		// 继承父线程的一些资源,如是否守护线程、优先级、上下文ClassLoader加载器。
		...

       // 获取当前上下文的资源堆栈数据
        this.inheritedAccessControlContext =  acc != null ? acc : AccessController.getContext();
        // 线程实际要执行的方法
        this.target = target;
		// 继承父线程的上下文资源
        this.inheritableThreadLocals = ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
    }

总结一下,就是继承了父线程的上下文ClassLoader,把要执行的方法传递给target,其他暂时不重要。

SecurityManager 类
The security manager is a class that allows applications to implement a security policy. It allows an application to determine, before performing a possibly unsafe or sensitive operation, what the operation is and whether it is being attempted in a security context that allows the operation to be performed. The application can allow or disallow the operation.
安全管理器是一个允许应用程序实现安全策略的类。它允许应用程序在执行可能不安全或敏感的操作之前确定该操作是什么,以及是否在允许执行该操作的安全上下文中尝试该操作。应用程序可以允许或不允许该操作。

AccessControlContext类
An AccessControlContext is used to make system resource access decisions based on the context it encapsulates.
AccessControlContext用于根据它封装的上下文做出系统资源访问决策。

enableContextClassLoaderOverride RuntimePermission的权限,init方法继承线程时会校验是否具有此权限
The context class loader is used by system code and extensions when they need to lookup resources that might not exist in the system class loader. Granting enableContextClassLoaderOverride permission would allow a subclass of Thread to override the methods that are used to get or set the context class loader for a particular thread.
当系统代码和扩展需要查找系统类装入器中可能不存在的资源时,将使用上下文类装入器。授予enableContextClassLoaderOverride权限将允许Thread的子类重写用于获取或设置特定线程的上下文类装入器的方法。

原始init源码
private void init(ThreadGroup g, Runnable target, String name,
                      long stackSize, AccessControlContext acc,
                      boolean inheritThreadLocals) {
        if (name == null) {
            throw new NullPointerException("name cannot be null");
        }

        this.name = name;

        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();
            }
        }

        // 校验是否有权限修改线程组资源
        g.checkAccess();

        // 校验是否具有修改父线程上下文资源的权限
        if (security != null) {
            if (isCCLOverridden(getClass())) {
                security.checkPermission(SUBCLASS_IMPLEMENTATION_PERMISSION);
            }
        }

        g.addUnstarted();
		
		// 继承父线程的资源,如是否守护线程、优先级、上下文资源ClassLoader、共享空间ThreadLocal
        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 (inheritThreadLocals && parent.inheritableThreadLocals != null)
            this.inheritableThreadLocals =
                ThreadLocal.createInheritedMap(parent.inheritableThreadLocals);
        // 设置栈大小
        this.stackSize = stackSize;

        // 线程id 自增的
        tid = nextThreadID();
    }

引申问题,线程获取了哪些上下文资源?contextClassLoader 又是什么?挖坑,有缘再填。参考资源contextClassLoader源码

线程是如何执行的?

在了解线程是如何初始化之后,我们知道了线程初始化时,会获取计算机上下文资源,会修改线程组信息,会校验是否有获取上下文资源的权限。那么初始化完成后,Java如何帮我们调用计算机资源,启动线程呢?

属性&方法

threadStatus int 线程状态

start方法做了什么(简化版)

总的来说比较简单,因为启动线程是c帮我们做的。

public synchronized void start() {
     // 线程状态!=new 抛异常 线程不可执行多次
     if (threadStatus != 0)
         throw new IllegalThreadStateException();

     // 线程组未执行线程减一
     group.add(this);

     boolean started = false;
     try {
     	 // native方法,可参照下面的文章
         start0();
         started = true;
     } finally {
         try {
             if (!started) {
                 group.threadStartFailed(this);
             }
         } catch (Throwable ignore) {
         }
     }
 }

分享
start0方法做了什么
JDK8的源代码
Java线程运行原理

Thread的常用方法

yeild 让出当前计算机cpu的执行权,但会参与下一次cpu的竞争。
join a线程正在运行,调用b.join() 则停止a线程执行,b线程开始执行。直到b线程执行结束,或者a线程被notify
sleep 线程休眠一段时间

  • 29
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值