Save This Page
Home » apache-harmony-6.0-src-r917296-snapshot » java » lang » [javadoc | source]
    1   /*
    2    *  Licensed to the Apache Software Foundation (ASF) under one or more
    3    *  contributor license agreements.  See the NOTICE file distributed with
    4    *  this work for additional information regarding copyright ownership.
    5    *  The ASF licenses this file to You under the Apache License, Version 2.0
    6    *  (the "License"); you may not use this file except in compliance with
    7    *  the License.  You may obtain a copy of the License at
    8    *
    9    *     http://www.apache.org/licenses/LICENSE-2.0
   10    *
   11    *  Unless required by applicable law or agreed to in writing, software
   12    *  distributed under the License is distributed on an "AS IS" BASIS,
   13    *  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
   14    *  See the License for the specific language governing permissions and
   15    *  limitations under the License.
   16    */
   17   
   18   package java.lang;
   19   
   20   import java.lang.ref.WeakReference;
   21   import java.lang.ref.Reference;
   22   import java.util.concurrent.atomic.AtomicInteger;
   23   
   24   /**
   25    * A variable for which each thread has its own value. Supports {@code null}
   26    * values.
   27    * 
   28    * @see java.lang.Thread
   29    * @author Bob Lee
   30    */
   31   public class ThreadLocal<T> {
   32   
   33       /* Thanks to Josh Bloch and Doug Lea for code reviews and impl advice. */
   34   
   35       /**
   36        * Creates a new thread local variable.
   37        */
   38       public ThreadLocal() {}
   39   
   40       /**
   41        * Returns the value of this variable for the current thread. If an entry
   42        * doesn't yet exist for this variable on this thread, this method will
   43        * create an entry, populating the value with the result of
   44        * {@link #initialValue()}.
   45        */
   46       @SuppressWarnings("unchecked")
   47       public T get() {
   48           // Optimized for the fast path.
   49           Thread currentThread = Thread.currentThread();
   50           Values values = values(currentThread);
   51           if (values != null) {
   52               Object[] table = values.table;
   53               int index = hash & values.mask;
   54               if (this.reference == table[index]) {
   55                   return (T) table[index + 1];
   56               }
   57           } else {
   58               values = initializeValues(currentThread);
   59           }
   60   
   61           return (T) values.getAfterMiss(this);
   62       }
   63   
   64       /**
   65        * Provides the initial value of this variable for the current thread.
   66        * The default implementation returns {@code null}.
   67        */
   68       protected T initialValue() {
   69           return null;
   70       }
   71   
   72       /**
   73        * Sets the value of this variable for the current thread. If set to
   74        * null, the value will be set to null and the underlying entry will still
   75        * be present.
   76        */
   77       public void set(T value) {
   78           Thread currentThread = Thread.currentThread();
   79           Values values = values(currentThread);
   80           if (values == null) {
   81               values = initializeValues(currentThread);
   82           }
   83           values.put(this, value);
   84       }
   85   
   86       /**
   87        * Removes the entry for this variable in the current thread. If this call
   88        * is followed by a {@link #get()} before a {@link #set(Object)},
   89        * {@code #get()} will call {@link #initialValue()} and create a new
   90        * entry with the resulting value.
   91        */
   92       public void remove() {
   93           Thread currentThread = Thread.currentThread();
   94           Values values = values(currentThread);
   95           if (values != null) {
   96               values.remove(this);
   97           }
   98       }
   99   
  100       /**
  101        * Creates Values instance for this thread and variable type.
  102        */
  103       Values initializeValues(Thread current) {
  104           return current.localValues = new Values();
  105       }
  106   
  107       /**
  108        * Gets Values instance for this thread and variable type.
  109        */
  110       Values values(Thread current) {
  111           return current.localValues;
  112       }
  113   
  114       /** Weak reference to this thread local instance. */
  115       private final Reference<ThreadLocal<T>> reference
  116               = new WeakReference<ThreadLocal<T>>(this);
  117   
  118       /** Hash counter. */
  119       private static AtomicInteger hashCounter = new AtomicInteger(0);
  120   
  121       /**
  122        * Internal hash. We deliberately don't bother with #hashCode().
  123        * Hashes must be even. This ensures that the result of
  124        * (hash & (table.length - 1)) points to a key and not a value.
  125        *
  126        * We increment by Doug Lea's Magic Number(TM) (*2 since keys are in
  127        * every other bucket) to help prevent clustering.
  128        */
  129       private final int hash = hashCounter.getAndAdd(0x61c88647 << 1);
  130   
  131       /**
  132        * Per-thread map of ThreadLocal instances to values.
  133        */
  134       static class Values {
  135   
  136           /**
  137            * Size must always be a power of 2.
  138            */
  139           private static final int INITIAL_SIZE = 16;
  140   
  141           /**
  142            * Placeholder for deleted entries.
  143            */
  144           private static final Object TOMBSTONE = new Object();
  145   
  146           /**
  147            * Map entries. Contains alternating keys (ThreadLocal) and values.
  148            * The length is always a power of 2.
  149            */
  150           private Object[] table;
  151   
  152           /** Used to turn hashes into indices. */
  153           private int mask;
  154   
  155           /** Number of live entries. */
  156           private int size;
  157   
  158           /** Number of tombstones. */
  159           private int tombstones;
  160   
  161           /** Maximum number of live entries and tombstones. */
  162           private int maximumLoad;
  163   
  164           /** Points to the next cell to clean up. */
  165           private int clean;
  166   
  167           /**
  168            * Constructs a new, empty instance.
  169            */
  170           Values() {
  171               initializeTable(INITIAL_SIZE);
  172               this.size = 0;
  173               this.tombstones = 0;
  174           }
  175   
  176           /**
  177            * Used for InheritableThreadLocals.
  178            */
  179           Values(Values fromParent) {
  180               this.table = fromParent.table.clone();
  181               this.mask = fromParent.mask;
  182               this.size = fromParent.size;
  183               this.tombstones = fromParent.tombstones;
  184               this.maximumLoad = fromParent.maximumLoad;
  185               this.clean = fromParent.clean;
  186               inheritValues(fromParent);
  187           }
  188   
  189           /**
  190            * Inherits values from a parent thread.
  191            */
  192           @SuppressWarnings({"unchecked"})
  193           private void inheritValues(Values fromParent) {
  194               // Transfer values from parent to child thread.
  195               Object[] table = this.table;
  196               for (int i = table.length - 2; i >= 0; i -= 2) {
  197                   Object k = table[i];
  198   
  199                   if (k == null || k == TOMBSTONE) {
  200                       // Skip this entry.
  201                       continue;
  202                   }
  203   
  204                   // The table can only contain null, tombstones and references.
  205                   Reference<InheritableThreadLocal<?>> reference
  206                           = (Reference<InheritableThreadLocal<?>>) k;
  207                   // Raw type enables us to pass in an Object below.
  208                   InheritableThreadLocal key = reference.get();
  209                   if (key != null) {
  210                       // Replace value with filtered value.
  211                       // We should just let exceptions bubble out and tank
  212                       // the thread creation
  213                       table[i + 1] = key.childValue(fromParent.table[i + 1]);
  214                   } else {
  215                       // The key was reclaimed.
  216                       table[i] = TOMBSTONE;
  217                       table[i + 1] = null;
  218                       fromParent.table[i] = TOMBSTONE;
  219                       fromParent.table[i + 1] = null;
  220   
  221                       tombstones++;
  222                       fromParent.tombstones++;
  223   
  224                       size--;
  225                       fromParent.size--;
  226                   }
  227               }
  228           }
  229   
  230           /**
  231            * Creates a new, empty table with the given capacity.
  232            */
  233           private void initializeTable(int capacity) {
  234               this.table = new Object[capacity << 1];
  235               this.mask = table.length - 1;
  236               this.clean = 0;
  237               this.maximumLoad = capacity * 2 / 3; // 2/3
  238           }
  239   
  240           /**
  241            * Cleans up after garbage-collected thread locals.
  242            */
  243           private void cleanUp() {
  244               if (rehash()) {
  245                   // If we rehashed, we needn't clean up (clean up happens as
  246                   // a side effect).
  247                   return;
  248               }
  249   
  250               if (size == 0) {
  251                   // No live entries == nothing to clean.
  252                   return;
  253               }
  254   
  255               // Clean log(table.length) entries picking up where we left off
  256               // last time.
  257               int index = clean;
  258               Object[] table = this.table;
  259               for (int counter = table.length; counter > 0; counter >>= 1,
  260                       index = next(index)) {
  261                   Object k = table[index];
  262   
  263                   if (k == TOMBSTONE || k == null) {
  264                       continue; // on to next entry
  265                   }
  266   
  267                   // The table can only contain null, tombstones and references.
  268                   @SuppressWarnings("unchecked")
  269                   Reference<ThreadLocal<?>> reference
  270                           = (Reference<ThreadLocal<?>>) k;
  271                   if (reference.get() == null) {
  272                       // This thread local was reclaimed by the garbage collector.
  273                       table[index] = TOMBSTONE;
  274                       table[index + 1] = null;
  275                       tombstones++;
  276                       size--;
  277                   }
  278               }
  279   
  280               // Point cursor to next index.
  281               clean = index;
  282           }
  283   
  284           /**
  285            * Rehashes the table, expanding or contracting it as necessary.
  286            * Gets rid of tombstones. Returns true if a rehash occurred.
  287            * We must rehash every time we fill a null slot; we depend on the
  288            * presence of null slots to end searches (otherwise, we'll infinitely
  289            * loop).
  290            */
  291           private boolean rehash() {
  292               if (tombstones + size < maximumLoad) {
  293                   return false;
  294               }
  295   
  296               int capacity = table.length >> 1;
  297   
  298               // Default to the same capacity. This will create a table of the
  299               // same size and move over the live entries, analogous to a
  300               // garbage collection. This should only happen if you churn a
  301               // bunch of thread local garbage (removing and reinserting
  302               // the same thread locals over and over will overwrite tombstones
  303               // and not fill up the table).
  304               int newCapacity = capacity;
  305   
  306               if (size > (capacity >> 1)) {
  307                   // More than 1/2 filled w/ live entries.
  308                   // Double size.
  309                   newCapacity = capacity << 1;
  310               }
  311   
  312               Object[] oldTable = this.table;
  313   
  314               // Allocate new table.
  315               initializeTable(newCapacity);
  316   
  317               // We won't have any tombstones after this.
  318               this.tombstones = 0;
  319   
  320               // If we have no live entries, we can quit here.
  321               if (size == 0) {
  322                   return true;
  323               }
  324   
  325               // Move over entries.
  326               for (int i = oldTable.length - 2; i >= 0; i -= 2) {
  327                   Object k = oldTable[i];
  328                   if (k == null || k == TOMBSTONE) {
  329                       // Skip this entry.
  330                       continue;
  331                   }
  332   
  333                   // The table can only contain null, tombstones and references.
  334                   @SuppressWarnings("unchecked")
  335                   Reference<ThreadLocal<?>> reference
  336                           = (Reference<ThreadLocal<?>>) k;
  337                   ThreadLocal<?> key = reference.get();
  338                   if (key != null) {
  339                       // Entry is still live. Move it over.
  340                       add(key, oldTable[i + 1]);
  341                   } else {
  342                       // The key was reclaimed.
  343                       size--;
  344                   }
  345               }
  346   
  347               return true;
  348           }
  349   
  350           /**
  351            * Adds an entry during rehashing. Compared to put(), this method
  352            * doesn't have to clean up, check for existing entries, account for
  353            * tombstones, etc.
  354            */
  355           void add(ThreadLocal<?> key, Object value) {
  356               for (int index = key.hash & mask;; index = next(index)) {
  357                   Object k = table[index];
  358                   if (k == null) {
  359                       table[index] = key.reference;
  360                       table[index + 1] = value;
  361                       return;
  362                   }
  363               }
  364           }
  365   
  366           /**
  367            * Sets entry for given ThreadLocal to given value, creating an
  368            * entry if necessary.
  369            */
  370           void put(ThreadLocal<?> key, Object value) {
  371               cleanUp();
  372   
  373               // Keep track of first tombstone. That's where we want to go back
  374               // and add an entry if necessary.
  375               int firstTombstone = -1;
  376   
  377               for (int index = key.hash & mask;; index = next(index)) {
  378                   Object k = table[index];
  379   
  380                   if (k == key.reference) {
  381                       // Replace existing entry.
  382                       table[index + 1] = value;
  383                       return;
  384                   }
  385   
  386                   if (k == null) {
  387                       if (firstTombstone == -1) {
  388                           // Fill in null slot.
  389                           table[index] = key.reference;
  390                           table[index + 1] = value;
  391                           size++;
  392                           return;
  393                       }
  394   
  395                       // Go back and replace first tombstone.
  396                       table[firstTombstone] = key.reference;
  397                       table[firstTombstone + 1] = value;
  398                       tombstones--;
  399                       size++;
  400                       return;
  401                   }
  402   
  403                   // Remember first tombstone.
  404                   if (firstTombstone == -1 && k == TOMBSTONE) {
  405                       firstTombstone = index;
  406                   }
  407               }
  408           }
  409   
  410           /**
  411            * Gets value for given ThreadLocal after not finding it in the first
  412            * slot.
  413            */
  414           Object getAfterMiss(ThreadLocal<?> key) {
  415               Object[] table = this.table;
  416               int index = key.hash & mask;
  417   
  418               // If the first slot is empty, the search is over.
  419               if (table[index] == null) {
  420                   Object value = key.initialValue();
  421   
  422                   // If the table is still the same and the slot is still empty...
  423                   if (this.table == table && table[index] == null) {
  424                       table[index] = key.reference;
  425                       table[index + 1] = value;
  426                       size++;
  427   
  428                       cleanUp();
  429                       return value;
  430                   }
  431   
  432                   // The table changed during initialValue().
  433                   put(key, value);
  434                   return value;
  435               }
  436   
  437               // Keep track of first tombstone. That's where we want to go back
  438               // and add an entry if necessary.
  439               int firstTombstone = -1;
  440   
  441               // Continue search.
  442               for (index = next(index);; index = next(index)) {
  443                   Object reference = table[index];
  444                   if (reference == key.reference) {
  445                       return table[index + 1];
  446                   }
  447   
  448                   // If no entry was found...
  449                   if (reference == null) {
  450                       Object value = key.initialValue();
  451   
  452                       // If the table is still the same...
  453                       if (this.table == table) {
  454                           // If we passed a tombstone and that slot still
  455                           // contains a tombstone...
  456                           if (firstTombstone > -1
  457                                   && table[firstTombstone] == TOMBSTONE) {
  458                               table[firstTombstone] = key.reference;
  459                               table[firstTombstone + 1] = value;
  460                               tombstones--;
  461                               size++;
  462   
  463                               // No need to clean up here. We aren't filling
  464                               // in a null slot.
  465                               return value;
  466                           }
  467   
  468                           // If this slot is still empty...
  469                           if (table[index] == null) {
  470                               table[index] = key.reference;
  471                               table[index + 1] = value;
  472                               size++;
  473   
  474                               cleanUp();
  475                               return value;
  476                           }
  477                       }
  478   
  479                       // The table changed during initialValue().
  480                       put(key, value);
  481                       return value;
  482                   }
  483   
  484                   if (firstTombstone == -1 && reference == TOMBSTONE) {
  485                       // Keep track of this tombstone so we can overwrite it.
  486                       firstTombstone = index;
  487                   }
  488               }
  489           }
  490   
  491           /**
  492            * Removes entry for the given ThreadLocal.
  493            */
  494           void remove(ThreadLocal<?> key) {
  495               cleanUp();
  496   
  497               for (int index = key.hash & mask;; index = next(index)) {
  498                   Object reference = table[index];
  499   
  500                   if (reference == key.reference) {
  501                       // Success!
  502                       table[index] = TOMBSTONE;
  503                       table[index + 1] = null;
  504                       tombstones++;
  505                       size--;
  506                       return;
  507                   }
  508   
  509                   if (reference == null) {
  510                       // No entry found.
  511                       return;
  512                   }
  513               }
  514           }
  515   
  516           /**
  517            * Gets the next index. If we're at the end of the table, we wrap back
  518            * around to 0.
  519            */
  520           private int next(int index) {
  521               return (index + 2) & mask;
  522           }
  523       }
  524   }

Save This Page
Home » apache-harmony-6.0-src-r917296-snapshot » java » lang » [javadoc | source]