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 org.apache.harmony.tests.java.lang; 19 20 import junit.framework.TestCase; 21 import java.util.concurrent.atomic.AtomicReference; 22 23 public class ThreadLocalTest extends TestCase { 24 25 /** 26 * java.lang.ThreadLocal#ThreadLocal() 27 */ 28 public void test_Constructor() { 29 new ThreadLocal<Object>(); 30 } 31 32 /** 33 * java.lang.ThreadLocal#remove() 34 */ 35 public void test_remove() { 36 ThreadLocal<String> tl = new ThreadLocal<String>() { 37 @Override 38 protected String initialValue() { 39 return "initial"; 40 } 41 }; 42 43 assertEquals("initial", tl.get()); 44 tl.set("fixture"); 45 assertEquals("fixture", tl.get()); 46 tl.remove(); 47 assertEquals("initial", tl.get()); 48 } 49 50 /** 51 * java.lang.ThreadLocal#get() 52 */ 53 public void test_get() { 54 // Test for method java.lang.Object java.lang.ThreadLocal.get() 55 ThreadLocal<Object> l = new ThreadLocal<Object>(); 56 assertNull("ThreadLocal's initial value is null", l.get()); 57 58 // The ThreadLocal has to run once for each thread that touches the 59 // ThreadLocal 60 final Object INITIAL_VALUE = "'foo'"; 61 final ThreadLocal<Object> l1 = new ThreadLocal<Object>() { 62 @Override 63 protected Object initialValue() { 64 return INITIAL_VALUE; 65 } 66 }; 67 68 assertTrue("ThreadLocal's initial value should be " + INITIAL_VALUE 69 + " but is " + l1.get(), l1.get() == INITIAL_VALUE); 70 71 // We need this because inner types cannot assign to variables in 72 // container method. But assigning to object slots in the container 73 // method is ok. 74 class ResultSlot { 75 public Object result = null; 76 } 77 78 final ResultSlot THREADVALUE = new ResultSlot(); 79 Thread t = new Thread() { 80 @Override 81 public void run() { 82 THREADVALUE.result = l1.get(); 83 } 84 }; 85 86 // Wait for the other Thread assign what it observes as the value of the 87 // variable 88 t.start(); 89 try { 90 t.join(); 91 } catch (InterruptedException ie) { 92 fail("Interrupted!!"); 93 } 94 95 assertTrue("ThreadLocal's initial value in other Thread should be " 96 + INITIAL_VALUE, THREADVALUE.result == INITIAL_VALUE); 97 98 /* Regression test for implementation vulnerability reported 99 * on Harmony dev list. 100 */ 101 ThreadLocal<Object> thrVar = new ThreadLocal<Object>() { 102 public int hashCode() { 103 fail("ThreadLocal should not be asked for it's hashCode"); 104 return 0; // never reached 105 } 106 }; 107 thrVar.get(); 108 } 109 110 /** 111 * java.lang.ThreadLocal#set(java.lang.Object) 112 */ 113 public void test_setLjava_lang_Object() { 114 // Test for method void java.lang.ThreadLocal.set(java.lang.Object) 115 116 final Object OBJ = new Object(); 117 final ThreadLocal<Object> l = new ThreadLocal<Object>(); 118 l.set(OBJ); 119 assertTrue("ThreadLocal's initial value is " + OBJ, l.get() == OBJ); 120 121 // We need this because inner types cannot assign to variables in 122 // container method. 123 // But assigning to object slots in the container method is ok. 124 class ResultSlot { 125 public Object result = null; 126 } 127 128 final ResultSlot THREADVALUE = new ResultSlot(); 129 Thread t = new Thread() { 130 @Override 131 public void run() { 132 THREADVALUE.result = l.get(); 133 } 134 }; 135 136 // Wait for the other Thread assign what it observes as the value of the 137 // variable 138 t.start(); 139 try { 140 t.join(); 141 } catch (InterruptedException ie) { 142 fail("Interrupted!!"); 143 } 144 145 // ThreadLocal is not inherited, so the other Thread should see it as 146 // null 147 assertNull("ThreadLocal's value in other Thread should be null", 148 THREADVALUE.result); 149 150 } 151 152 /** 153 * java.lang.ThreadLocal#withInitial() 154 */ 155 public void test_withInitial() { 156 // The ThreadLocal has to run once for each thread that touches the 157 // ThreadLocal 158 final String INITIAL_VALUE = "'foo'"; 159 final String OTHER_VALUE = "'bar'"; 160 final ThreadLocal<String> l1 = ThreadLocal.withInitial(() -> INITIAL_VALUE); 161 162 assertSame(INITIAL_VALUE, l1.get()); 163 164 l1.set(OTHER_VALUE); 165 assertSame(OTHER_VALUE, l1.get()); 166 167 assertTrue("ThreadLocal's value should be " + OTHER_VALUE 168 + " but is " + l1.get(), l1.get() == OTHER_VALUE); 169 170 AtomicReference<String> threadValue = new AtomicReference<String>(); 171 172 Thread t = new Thread() { 173 @Override 174 public void run() { 175 threadValue.set(l1.get()); 176 } 177 }; 178 179 // Wait for the other Thread assign what it observes as the value of the 180 // variable 181 t.start(); 182 try { 183 t.join(); 184 } catch (InterruptedException ie) { 185 fail("Interrupted!!"); 186 } 187 188 assertSame(INITIAL_VALUE, threadValue.get()); 189 } 190 } 191