Java如何创建主线程

15

我对Java技术还很陌生。我知道在Java中只有两种创建 Thread 的方法:

  • 继承 Thread 类
  • 实现 Runnable 接口

所以这是创建 Thread 的唯二方式。但当我们启动程序时,JVM 会启动一个主 Thread。我认为即使是JVM也必须遵循创建主 Thread 的规则,也就是说创建主线程的JVM要么继承 Thread 类,要么实现 Runnable 接口。

public class MainThreadExample {

    public static void main(String[] args) {

        Thread t=Thread.currentThread();            
        System.out.println(t.getName());            
    }
}

我尽力了,但是不知道JVM如何创建这个主对象。我已经完全查看了主类(sun.tool.jar),我知道这是负责主线程的类。但是在Google搜索了很多网页后仍然无法理解。所以请帮忙,如果可能的话,请提供示例或链接。
附言:我正在学习Java技术,我不应该太过关注它是如何创建主函数的,因为这是一个设计问题。但我认为这是一个合理的问题。

1
我猜这是Thread的匿名子类。 - John Dvorak
t.getClass().getFullName() 是什么意思? - John Dvorak
没有任何规定说如果我们看不到Runnable和Thread,那么就没有任何线程。一个方法可以被一个线程触发,你也可以通过反射运行每个线程,只要它们不是void run()。JVM会创建一个线程,在线程内部调用主方法。 - user2511414
1
我认为Java运行时本身并不必须遵循Java创建线程的规则,因为它并非用Java实现。我怀疑垃圾收集器也在自己的线程中运行,并且(据我所知)GC执行一些Java无法完成的操作。 - Reinstate Monica -- notmaynard
3
与回答无关,我发现了一篇关于Java线程的详细文章。我认为你会喜欢阅读。http://blog.jamesdbloom.com/JVMInternals.html - ata
2个回答

21

java.lang.Thread 的一个实例并不是一个线程,它可以用来表示 JVM 中的执行线程,但 JVM 完全可以在不使用 Thread 类的情况下创建线程。

这就是主线程的情况:JVM 创建它,稍后创建一个 java.lang.Thread 实例来代表它。

在 Hotspot JVM 中,Threads 类中有很多与线程相关的代码,该类定义在src/share/vm/runtime/thread.hppsrc/share/vm/runtime/thread.cpp中。JVM 的启动调用静态的 Threads::create_vm 函数,该函数已经在操作系统设置的线程中运行。在该函数内部,我们可以找到:

(src/share/vm/runtime/thread.cpp)
3191   // Attach the main thread to this os thread
3192   JavaThread* main_thread = new JavaThread();
3193   main_thread->set_thread_state(_thread_in_vm);
3194   // must do this before set_active_handles and initialize_thread_local_storage
3195   // Note: on solaris initialize_thread_local_storage() will (indirectly)
3196   // change the stack size recorded here to one based on the java thread
3197   // stacksize. This adjusted size is what is used to figure the placement
3198   // of the guard pages.
3199   main_thread->record_stack_base_and_size();
3200   main_thread->initialize_thread_local_storage();

JavaThread类显然用于簿记;它将操作系统或VM线程与Java线程对象相关联。Java对象显然还不存在。然后代码继续初始化各种其他东西,稍后在同一函数中我们找到了这个:

3335     // Initialize java_lang.System (needed before creating the thread)
3336     if (InitializeJavaLangSystem) {
3337       initialize_class(vmSymbols::java_lang_System(), CHECK_0);
3338       initialize_class(vmSymbols::java_lang_ThreadGroup(), CHECK_0);
3339       Handle thread_group = create_initial_thread_group(CHECK_0);
3340       Universe::set_main_thread_group(thread_group());
3341       initialize_class(vmSymbols::java_lang_Thread(), CHECK_0);
3342       oop thread_object = create_initial_thread(thread_group, main_thread, CHECK_0);
3343       main_thread->set_threadObj(thread_object);
3344       // Set thread status to running since main thread has
3345       // been started and running.
3346       java_lang_Thread::set_thread_status(thread_object,
3347                                           java_lang_Thread::RUNNABLE);

换句话说,它初始化了 SystemThreadGroupThread 类,然后创建了一个由 thread_object 引用的 Thread 实例(第3342行),并为主要的 JavaThread 设置了 Thread 实例。

如果你想知道 create_initial_thread 做了什么,显然它分配了 Thread 实例,在 Thread 实例的私有字段 eetop 中存储指向 JavaThread (C++) 对象的指针,将线程优先级字段设置为正常,调用 Thread(ThreadGroup group,String name) 构造函数,并返回该实例:

 967 // Creates the initial Thread
 968 static oop create_initial_thread(Handle thread_group, JavaThread* thread, TRAPS) {
 969   klassOop k = SystemDictionary::resolve_or_fail(vmSymbols::java_lang_Thread(), true, CHECK_     NULL);
 970   instanceKlassHandle klass (THREAD, k);
 971   instanceHandle thread_oop = klass->allocate_instance_handle(CHECK_NULL);
 972 
 973   java_lang_Thread::set_thread(thread_oop(), thread);
 974   java_lang_Thread::set_priority(thread_oop(), NormPriority);
 975   thread->set_threadObj(thread_oop());
 976 
 977   Handle string = java_lang_String::create_from_str("main", CHECK_NULL);
 978 
 979   JavaValue result(T_VOID);
 980   JavaCalls::call_special(&result, thread_oop,
 981                                    klass,
 982                                    vmSymbols::object_initializer_name(),
 983                                    vmSymbols::threadgroup_string_void_signature(),
 984                                    thread_group,
 985                                    string,
 986                                    CHECK_NULL);
 987   return thread_oop();
 988 }

现在,这就是Hotspot虚拟机的工作原理。其他实现,比如IBM J9、Oracle JRockit或Azul Zing,可能也会做类似的事情。


非常感谢您回答Joni的问题。但是,您能否稍微详细解释一下Java如何创建Java.lang.Thread实例来表示它呢?我已经查看了整个main和Thread类,但没有理解。 - Arun
主线程和代表它的java.lang.Thread对象必须在本地代码中创建。我将查看OpenJDK源代码,也许我可以确定位置。 - Joni
这将是非常有帮助的..非常感谢您的帮助。 - Arun
请查看更新,如果有不清楚的地方,请问。当Java和C++对象一起混合使用时,解释起来会变得很复杂。 - Joni

3
我认为确切的机制是与JVM相关的。规范有点模糊,但是Thread Javadoc提供了以下内容:

当Java虚拟机启动时,通常有一个非守护线程(通常调用某个指定类的main方法)。

如何映射到Thread类的实例似乎没有明确规定。


当你说“规范有点模糊”时,你指的是JLS/JVMS的哪一部分? - Pacerier

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接