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