栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 系统运维 > 运维 > Linux

为什么使用start方法启动Java的Thread线程?

Linux 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

为什么使用start方法启动Java的Thread线程?

一、简介

在Java代码当中,当我们需要开启子线程去处理一些任务的时候,往往是调用Thread对象的start方法,这样Thread实例中的Runnable对象的run方法就会在一个新的线程当中执行;

// 创建一个线程
Thread thread = new Thread(new Runnable() {
			
	@Override
	public void run() {
		System.out.println("working in " + Thread.currentThread().getName());
	}
});

// 在什么线程调用,run方法的任务就在什么线程执行
thread.run();

// 在一个新的线程中执行run方法中的任务
thread.start();
二、分析run()方法

如下代码可见,当我们直接调用run方法的时候,就相当于实例直接调用一个普通的方法一样,所以无论我们在什么线程中调用run方法,run方法中的业务就在什么线程执行,并不会说启动一个新的线程去执行run方法中的任务;

// Thread.class中的run方法,target为Runnable实例
@Override 
public void run() {
    if (target != null) {
        target.run();
    }
}
三、分析start()方法

如下我们直接来看Thread.class中的代码;

public synchronized void start() {
    
    if (threadStatus != 0)
        throw new IllegalThreadStateException();

    
    // 1. 将当前线程实例添加到ThreadGroup对象group中
    group.add(this);

    boolean started = false;
    try {
        // 2. 调用native方法start0()
        start0();
        started = true;
    } finally {
        try {
            if (!started) {
                group.threadStartFailed(this);
            }
        } catch (Throwable ignore) {
            
        }
    }
}

// native 方法
private native void start0();

看上面代码的注释1那里,我们来看下Thread.class代码里面group是哪里来的

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();
    // 1. 从System类中获取安全管理器
    SecurityManager security = System.getSecurityManager();
    if (g == null) {
        

        
        if (security != null) {
            // 2. 从安全管理器中过去ThreadGroup对象
            g = security.getThreadGroup();
        }

        
        if (g == null) {
            g = parent.getThreadGroup();
        }
    }

    g.addUnstarted();

    this.group = g;
        
    // 省略一部分代码
    ···
}

从上面注释1,2可以看出,Thread实例中的ThreadGroup实例g主要是从底层代码中获取的,即group.add(this)执行之后,将当前线程传给了底层系统去管理

下面看下start0()方法,因为start0()方法为Native方法,看下是怎么实现的,如下为src/main/native/Thread.c的代码

static JNINativeMethod methods[] = {
    // 从这里我们可以看到start0方法主要JVM_StartThread的一个方法引用
    {"start0",           "(JZ)V",      (void *)&JVM_StartThread},
    {"setPriority0",     "(I)V",       (void *)&JVM_SetThreadPriority},
    {"yield",            "()V",        (void *)&JVM_Yield},
    {"sleep",            "(Ljava/lang/Object;J)V",       (void *)&JVM_Sleep},
    {"currentThread",    "()" THD,     (void *)&JVM_CurrentThread},
    {"interrupt0",       "()V",        (void *)&JVM_Interrupt},
    {"isInterrupted",    "(Z)Z",       (void *)&JVM_IsInterrupted},
    {"holdsLock",        "(" OBJ ")Z", (void *)&JVM_HoldsLock},
    {"setNativeName",    "(" STR ")V", (void *)&JVM_SetNativeThreadName},
};

下面一下JVM_StartThread的情况

// 如下为/openjdkjvm/OpenjdkJvm.cc中的代码
JNIEXPORT void JVM_StartThread(JNIEnv* env, jobject jthread, jlong stack_size, jboolean daemon) {
  art::Thread::CreateNativeThread(env, jthread, stack_size, daemon == JNI_TRUE);
}


// 如下为/runtime/thread.cc中创建native线程的代码
void Thread::CreateNativeThread(JNIEnv* env, jobject java_peer, size_t stack_size, bool is_daemon) {
    ···
    // 这里就不做展开了
}

总结:从上面代码可以看出,Thread调用start的时候,将thread实例传给虚拟机持有,然后调用native创建一个新的线程,由虚拟机进行调度。

水平有限,有误请指正!

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/828166.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号