Class ThreadLocalDirectory<AGGREGATOR,​SAMPLE>


  • public final class ThreadLocalDirectory<AGGREGATOR,​SAMPLE>
    extends java.lang.Object
    A class for multiple producers and potentially multiple consumers (usually only one).

    The consuming threads always unregisters the data producers when doing fetch(). This is the reason for having to do update through the directory. The reason for this is otherwise, we would either get reference leaks from registered objects belonging to dead threads if we did not unregister instances, otherwise the sampling thread would have to unregister the instance, and then we would create a memory relationship between all producing threads, which is exactly what this class aims to avoid.

    A complete example from a test:

     private static class SumUpdater implements ThreadLocalDirectory.Updater<Integer, Integer> {
    
         @Override
         public Integer update(Integer current, Integer x) {
             return Integer.valueOf(current.intValue() + x.intValue());
         }
    
         @Override
         public Integer createGenerationInstance(Integer previous) {
             return Integer.valueOf(0);
         }
     }
    
     ... then the producers does (where r is in instance of
     ThreadLocalDirectory)...
    
     @Override
     public void run() {
         LocalInstance<Integer, Integer> s = r.getLocalInstance();
         for (int i = 0; i < 500; ++i) {
             r.update(Integer.valueOf(i), s);
         }
     }
    
     ... and the consumer...
    
     List<Integer> measurements = s.fetch()
     

    Invoking r.fetch() will produce a list of integers from all the participating threads at any time.

    Refer to e.g. com.yahoo.search.statistics.PeakQpsSearcher for a production example.

    Author:
    Steinar Knutsen
    • Method Detail

      • fetch

        public java.util.List<AGGREGATOR> fetch()
        Fetch the current set of sampled data, and reset state of all thread local instances. The producer threads will not alter data in the list returned from this method.
        Returns:
        a list of data from all producer threads
      • view

        public java.util.List<AGGREGATOR> view()
        Get a view of the current data. This requires this ThreadLocalDirectory to have been instantiated with an updater implementing ObservableUpdater.
        Returns:
        a list of a copy of the current data in all producer threads
        Throws:
        java.lang.IllegalStateException - if the updater does not implement ThreadLocalDirectory.ObservableUpdater
      • getLocalInstance

        public LocalInstance<AGGREGATOR,​SAMPLE> getLocalInstance()
        Expose the thread local for the running thread, for use in conjunction with update(SAMPLE, LocalInstance<AGGREGATOR, SAMPLE>).
        Returns:
        the current thread's local instance
      • update

        public void update​(SAMPLE x)
        Input data from a producer thread.
        Parameters:
        x - the data to insert
      • update

        public void update​(SAMPLE x,
                           LocalInstance<AGGREGATOR,​SAMPLE> localInstance)
        Update a value with a given thread local instance.

        If a producer thread is to insert a series of data, it is desirable to limit the number of memory transactions to the theoretical minimum. Since reading a thread local is the memory equivalence of reading a volatile, it is then useful to avoid re-reading the running threads' input instance. For this scenario, fetch the running thread's instance with getLocalInstance(), and then insert the produced data with the multiple calls necessary to update(SAMPLE, LocalInstance<AGGREGATOR, SAMPLE>).

        Parameters:
        x - the data to insert
        localInstance - the local data insertion instance