Class ThreadService

java.lang.Object
java.lang.ThreadLocal<SoftReference<ThreadContext>>
org.jruby.internal.runtime.ThreadService

public class ThreadService extends ThreadLocal<SoftReference<ThreadContext>>
ThreadService maintains references to all JRuby-specific thread data structures needed for Ruby's threading API and for JRuby's execution. The main structures are:
  • ThreadContext, which contains frames, scopes, etc needed for Ruby execution
  • RubyThread, the Ruby object representation of a thread's state
  • RubyThreadGroup, which represents a group of Ruby threads
  • RubyNativeThread, used to wrap threads owned by the current Ruby runtime
  • AdoptedNativeThread, used to wrap threads managed outside of JRuby
In order to ensure these structures do not linger after the thread has terminated, most of them are either weakly or softly referenced. The references associated with these structures are:
  • ThreadService is itself a ThreadLocal, which holds a soft reference to a ThreadContext. So the thread's locals softly reference ThreadContext. We use a soft reference to keep ThreadContext instances from going away too quickly when a Java thread leaves Ruby space completely, which would otherwise result in a lot of ThreadContext object churn.
  • ThreadService maintains a weak map from the actual java.lang.Thread instance to the associated RubyThread. The map is weak-keyyed, so it will not prevent the collection of the associated Thread. The associated RubyThread will remain alive as long as the Thread and this ThreadService instance are both alive, maintaining the external thread's identity in Ruby-land.
  • RubyThread has a weak reference to its to ThreadContext.
  • ThreadContext has a hard reference to its associated RubyThread. Ignoring other references, this will usually mean RubyThread is softly reachable via the soft threadlocal reference to ThreadContext in ThreadService.
  • RubyThreadGroup has hard references to threads it owns. The thread removes itself on termination (if it's a Ruby thread) or when the ThreadContext is collected (as in the case of "adopted" Java threads.
These data structures can come to life in one of two ways:
  • A Ruby thread is started. This constructs a new RubyThread object, which calls to ThreadService to initialize a ThreadContext and appropriate mappings in all ThreadService's structures. The body of the thread is wrapped with a finally block that will forcibly unregister the thread and all related structures from ThreadService.
  • A Java thread enters Ruby by doing a call. The thread is "adopted", and gains a RubyThread instance, a ThreadContext instance, and all associated mappings in ThreadService. Since we don't know when the thread has "left" Ruby permanently, no forcible unregistration is attempted for the various structures and maps. However, they should not be hard-rooted; the ThreadContext is only softly reachable at best if no calls are in-flight, so it will collect. Its collection will release the reference to RubyThread, and its finalizer will unregister that RubyThread from its RubyThreadGroup. With the RubyThread gone, the Thread-to-RubyThread map will eventually clear, releasing the hard reference to the Thread itself.
    • Field Details

      • runtime

        private final Ruby runtime
      • mainContext

        private ThreadContext mainContext
        A hard reference to the "main" context, so we always have one waiting for "main" thread execution.
      • rubyThreadGroup

        private final ThreadGroup rubyThreadGroup
        The Java thread group into which we register all Ruby threads. This is distinct from the RubyThreadGroup, which is simply a mutable collection of threads.
      • rubyThreadMap

        private final Map<Thread,RubyThread> rubyThreadMap
        A map from a Java Thread to its RubyThread instance. This is a synchronized WeakHashMap, so it weakly references its keys; this means that when the Thread goes away, eventually its entry in this map will follow.
      • criticalLock

        private final ReentrantLock criticalLock
      • threadCount

        private final AtomicLong threadCount
    • Constructor Details

      • ThreadService

        public ThreadService(Ruby runtime)
    • Method Details

      • teardown

        public void teardown()
      • initMainThread

        public void initMainThread()
      • getCurrentContext

        public final ThreadContext getCurrentContext()
        In order to provide an appropriate execution context for a given thread, we store ThreadContext instances in a threadlocal. This method is a utility to get at that threadlocal context from anywhere in the program it may not be immediately available. This method should be used sparingly, and if it is possible to pass ThreadContext on the argument list, it is preferable. Description of behavior The threadlocal does not actually contain the ThreadContext directly; instead, it contains a SoftReference that holds the ThreadContext. This is to allow new threads to enter the system and execute Ruby code with a valid context, but still allow that context to garbage collect if the thread stays alive much longer. We use SoftReference here because WeakReference is collected too quickly, resulting in very expensive ThreadContext churn (and this originally lead to JRUBY-2261's leak of adopted RubyThread instances).
        Returns:
        The ThreadContext instance for the current thread, or a new one if none has previously been created or the old ThreadContext has been collected.
      • getCurrentContext

        public static ThreadContext getCurrentContext(ThreadService service)
      • adoptLoop

        private static ThreadContext adoptLoop(ThreadService service)
      • contextFromAdopt

        private static ThreadContext contextFromAdopt(ThreadService service)
      • adoptCurrentThread

        private RubyThread adoptCurrentThread()
      • registerNewThread

        public ThreadContext registerNewThread(RubyThread thread)
      • getMainThread

        public RubyThread getMainThread()
      • setMainThread

        public void setMainThread(Thread thread, RubyThread rubyThread)
      • getActiveRubyThreads

        public RubyThread[] getActiveRubyThreads()
      • associateThread

        public void associateThread(Thread thread, RubyThread rubyThread)
      • unregisterThread

        public void unregisterThread(RubyThread thread)
      • unregisterCurrentThread

        public void unregisterCurrentThread(ThreadContext context)
      • unregisterThreadImpl

        private void unregisterThreadImpl(ThreadContext context, Thread nativeThread)
      • disposeCurrentThread

        @Deprecated public void disposeCurrentThread()
        Deprecated.
      • incrementAndGetThreadCount

        public long incrementAndGetThreadCount()
      • getRubyThreadMap

        @Deprecated public Map<Object,RubyThread> getRubyThreadMap()
        Deprecated.
      • deliverEvent

        @Deprecated public void deliverEvent(RubyThread sender, RubyThread target, ThreadService.Event event)
        Deprecated.
      • getRubyThreadGroup

        @Deprecated public ThreadGroup getRubyThreadGroup()
        Deprecated.
      • getThreadContextForThread

        @Deprecated public ThreadContext getThreadContextForThread(RubyThread thread)
        Deprecated.
      • dissociateThread

        @Deprecated public void dissociateThread(Object thread)
        Deprecated.
      • setCurrentContext

        @Deprecated public final void setCurrentContext(ThreadContext context)
        Deprecated.
      • getPolling

        @Deprecated public boolean getPolling()
        Deprecated.
      • setCritical

        @Deprecated public void setCritical(boolean critical)
        Deprecated.
      • acquireCritical

        @Deprecated private void acquireCritical()
        Deprecated.
      • releaseCritical

        @Deprecated private void releaseCritical()
        Deprecated.
      • getCritical

        @Deprecated public boolean getCritical()
        Deprecated.