Home | History | Annotate | Download | only in concurrent
      1 /*
      2  * Copyright (c) 2016 Mockito contributors
      3  * This program is made available under the terms of the MIT License.
      4  */
      5 package org.mockito.internal.util.concurrent;
      6 
      7 /**
      8  * <p>
      9  * A detached local that allows for explicit control of setting and removing values from a thread-local
     10  * context.
     11  * </p>
     12  * Instances of this class are non-blocking and fully thread safe.
     13  */
     14 public class DetachedThreadLocal<T> implements Runnable {
     15 
     16     final WeakConcurrentMap<Thread, T> map;
     17 
     18     public DetachedThreadLocal(Cleaner cleaner) {
     19         switch (cleaner) {
     20             case THREAD:
     21             case MANUAL:
     22                 map = new WeakConcurrentMap<Thread, T>(cleaner == Cleaner.THREAD) {
     23                     @Override
     24                     protected T defaultValue(Thread key) {
     25                         return DetachedThreadLocal.this.initialValue(key);
     26                     }
     27                 };
     28                 break;
     29             case INLINE:
     30                 map = new WeakConcurrentMap.WithInlinedExpunction<Thread, T>() {
     31                     @Override
     32                     protected T defaultValue(Thread key) {
     33                         return DetachedThreadLocal.this.initialValue(key);
     34                     }
     35                 };
     36                 break;
     37             default:
     38                 throw new AssertionError();
     39         }
     40     }
     41 
     42     public T get() {
     43         return map.get(Thread.currentThread());
     44     }
     45 
     46     public void set(T value) {
     47         map.put(Thread.currentThread(), value);
     48     }
     49 
     50     public void clear() {
     51         map.remove(Thread.currentThread());
     52     }
     53 
     54     /**
     55      * Clears all thread local references for all threads.
     56      */
     57     public void clearAll() {
     58         map.clear();
     59     }
     60 
     61     /**
     62      * @param thread The thread to which this thread's thread local value should be pushed.
     63      * @return The value being set.
     64      */
     65     public T pushTo(Thread thread) {
     66         T value = get();
     67         if (value != null) {
     68             map.put(thread, inheritValue(value));
     69         }
     70         return value;
     71     }
     72 
     73     /**
     74      * @param thread The thread from which the thread thread local value should be fetched.
     75      * @return The value being set.
     76      */
     77     public T fetchFrom(Thread thread) {
     78         T value = map.get(thread);
     79         if (value != null) {
     80             set(inheritValue(value));
     81         }
     82         return value;
     83     }
     84 
     85     /**
     86      * @param thread The thread for which to set a thread-local value.
     87      * @return The value accociated with this thread.
     88      */
     89     public T get(Thread thread) {
     90         return map.get(thread);
     91     }
     92 
     93     /**
     94      * @param thread The thread for which to set a thread-local value.
     95      * @param value  The value to set.
     96      */
     97     public void define(Thread thread, T value) {
     98         map.put(thread, value);
     99     }
    100 
    101     /**
    102      * @param thread The thread for which an initial value is created.
    103      * @return The initial value for any thread local. If no default is set, the default value is {@code null}.
    104      */
    105     protected T initialValue(Thread thread) {
    106         return null;
    107     }
    108 
    109     /**
    110      * @param value The value that is inherited.
    111      * @return The inherited value.
    112      */
    113     protected T inheritValue(T value) {
    114         return value;
    115     }
    116 
    117     /**
    118      * @return The weak map that backs this detached thread local.
    119      */
    120     public WeakConcurrentMap<Thread, T> getBackingMap() {
    121         return map;
    122     }
    123 
    124     @Override
    125     public void run() {
    126         map.run();
    127     }
    128 
    129     /**
    130      * Determines the cleaning format. A reference is removed either by an explicitly started cleaner thread
    131      * associated with this instance ({@link Cleaner#THREAD}), as a result of interacting with this thread local
    132      * from any thread ({@link Cleaner#INLINE} or manually by submitting the detached thread local to a thread
    133      * ({@link Cleaner#MANUAL}).
    134      */
    135     public enum Cleaner {
    136         THREAD, INLINE, MANUAL
    137     }
    138 }
    139