Following threads are all created by main thread during VM init, so we have a valid current Thread in the VM and Java.
AttachListener:
- uses system_thread_group
- JavaCalls::construct_new_instance
- allocates Thread
- calls Thread(ThreadGroup tg, String name)
- call ThreadGroup.add(Thread t)
ThreadsLock {
- new JavaThread(entry)
- java_lang_Thread::set_thread(thread_oop(), thread);
** NO java_lang_Thread::set_priority **
- java_lang_Thread::set_daemon(thread_oop());
- thread->set_threadObj(thread_oop());
- Threads::add(thread);
- Thread::start(thread);
}
ServiceThread:
MonitorDeflationThread:
- uses system_thread_group
- JavaCalls::construct_new_instance
- allocates Thread
- calls Thread(ThreadGroup tg, String name)
ThreadsLock {
- new XXXThread(entry)
- java_lang_Thread::set_thread(thread_oop(), thread);
- java_lang_Thread::set_priority(thread_oop(), NearMaxPriority);
- java_lang_Thread::set_daemon(thread_oop());
- thread->set_threadObj(thread_oop());
- Threads::add(thread);
- Thread::start(thread);
}
** NO CALL to group.add(t) as these are hidden system threads.
NotificationThread:
SignalThread:
- uses system_thread_group
- JavaCalls::construct_new_instance
- allocates Thread
- calls Thread(ThreadGroup tg, String name)
- call ThreadGroup.add(Thread t) **** only difference from previous
ThreadsLock {
- new XXXThread(entry)
- java_lang_Thread::set_thread(thread_oop(), thread);
- java_lang_Thread::set_priority(thread_oop(), NearMaxPriority);
- java_lang_Thread::set_daemon(thread_oop());
- thread->set_threadObj(thread_oop());
- Threads::add(thread);
- Thread::start(thread);
}
JfrRecorderThread:
- calls up to JFR Java code to create j.l.Thread
- uses system thread group
ThreadsLock {
- new JavaThread(entry)
- java_lang_Thread::set_thread(thread_oop(), thread);
- java_lang_Thread::set_priority(thread_oop(), NormPriority); ** different
- java_lang_Thread::set_daemon(thread_oop());
- thread->set_threadObj(thread_oop());
- Threads::add(thread);
}
- Thread::start(thread);
JvmtiAgentThread:
- j.l.Thread already exists and is passed in
ThreadsLock {
- new JvmtiAgentThread(...)
- java_lang_Thread::set_thread(thread_oop(), thread);
- java_lang_Thread::set_priority(thread_oop(), priority); ** different
- java_lang_Thread::set_daemon(thread_oop());
- thread->set_threadObj(thread_oop());
- Threads::add(thread);
- Thread::start(thread);
}
CompilerThreads:
- j.l.Thread handling is a bit specialized
- code when holding ThreadsLock is basically the same, but priority is more complex
- calls os::set_native_priority directly
Differences:
- ThreadGroup.add
- Without a call to add() threads will not be listed in this TG and it is invisible.
- Some threads must be visible i.e. NotificationThread and SignalThread
- Priority value - most nearMaxPriority but JFR is Norm and CompilerThreads are special
- Note: we only set the priority field of the j.l.Thread, we don't call os::set_priority
- Some threads call os::set_priority at the start of the thread-entry method
- As a separate RFE we should fix this to that we do call os::set_priority consistently either before starting the target or when it runs
- Exception handling for Java calls can differ
- attachlistener uses special logic
- Use of vm_exit_during_initialization
- not for JfrRecorderThread, or JVMTI agent thread
Otherwise logic while holding Threads_lock is common and can be factored out:
- create XXXThread outside of ThreadsLock and pass in as JavaThread*
- so error handling is done at call site not in common code
j.l.Thread creation can also be factored out. Then the two parts combined for maximum reuse.
The basic pattern would be:
- obj = create threadObj
- thread = create XXXThread
- handle allocation failure
- startInternalThread(thread, obj)
This RFE will not look at the java.lang.Thread object creation to keep things simpler.