1 /*
  2  * Copyright (c) 2019, 2023, Oracle and/or its affiliates. All rights reserved.
  3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
  4  *
  5  * This code is free software; you can redistribute it and/or modify it
  6  * under the terms of the GNU General Public License version 2 only, as
  7  * published by the Free Software Foundation.
  8  *
  9  * This code is distributed in the hope that it will be useful, but WITHOUT
 10  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 11  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 12  * version 2 for more details (a copy is included in the LICENSE file that
 13  * accompanied this code).
 14  *
 15  * You should have received a copy of the GNU General Public License version
 16  * 2 along with this work; if not, write to the Free Software Foundation,
 17  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 18  *
 19  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 20  * or visit www.oracle.com if you need additional information or have any
 21  * questions.
 22  */
 23 
 24 /**
 25  * @test
 26  * @summary Test Virtual threads using thread locals
 27  * @library /test/lib
 28  * @enablePreview
 29  * @run junit ThreadLocals
 30  */
 31 
 32 import jdk.test.lib.thread.VThreadRunner;
 33 import org.junit.jupiter.api.Test;
 34 import static org.junit.jupiter.api.Assertions.*;
 35 
 36 class ThreadLocals {
 37     static final ThreadLocal<Object> LOCAL = new ThreadLocal<>();
 38     static final ThreadLocal<Object> INHERITED_LOCAL = new InheritableThreadLocal<>();
 39 
 40     /**
 41      * Basic test of thread local set/get.
 42      */
 43     @Test
 44     void testThreadLocal1() throws Exception {
 45         for (int i = 0; i < 10; i++) {
 46             VThreadRunner.run(() -> {
 47                 assertNull(LOCAL.get());
 48                 Object obj = new Object();
 49                 LOCAL.set(obj);
 50                 assertTrue(LOCAL.get() == obj);
 51             });
 52         }
 53     }
 54 
 55     /**
 56      * Test setting thread local before blocking operation.
 57      */
 58     @Test
 59     void testThreadLocal2() throws Exception {
 60         VThreadRunner.run(() -> {
 61             assertNull(LOCAL.get());
 62             Object obj = new Object();
 63             LOCAL.set(obj);
 64             try { Thread.sleep(100); } catch (InterruptedException e) { }
 65             assertTrue(LOCAL.get() == obj);
 66         });
 67     }
 68 
 69     /**
 70      * Test Thread that cannot set values for its copy of thread-locals.
 71      */
 72     @Test
 73     void testThreadLocal3() throws Exception {
 74         Object INITIAL_VALUE = new Object();
 75         ThreadLocal<Object> LOCAL2 = new ThreadLocal<>() {
 76             @Override
 77             protected Object initialValue() {
 78                 return INITIAL_VALUE;
 79             }
 80         };
 81         ThreadLocal<Object> INHERITED_LOCAL2 = new InheritableThreadLocal<>()  {
 82             @Override
 83             protected Object initialValue() {
 84                 return INITIAL_VALUE;
 85             }
 86         };
 87 
 88         VThreadRunner.run(VThreadRunner.NO_THREAD_LOCALS, () -> {
 89             assertThrows(UnsupportedOperationException.class, () -> LOCAL.set(null));
 90             assertThrows(UnsupportedOperationException.class, () -> LOCAL.set(new Object()));
 91             assertNull(LOCAL.get());
 92             LOCAL.remove();  // should not throw
 93 
 94             assertThrows(UnsupportedOperationException.class, () -> LOCAL2.set(null));
 95             assertThrows(UnsupportedOperationException.class, () -> LOCAL2.set(new Object()));
 96             assertTrue(LOCAL2.get() == INITIAL_VALUE);
 97             LOCAL2.remove();  // should not throw
 98 
 99             assertThrows(UnsupportedOperationException.class, () -> INHERITED_LOCAL.set(null));
100             assertThrows(UnsupportedOperationException.class, () -> INHERITED_LOCAL.set(new Object()));
101             assertNull(INHERITED_LOCAL.get());
102             INHERITED_LOCAL.remove();  // should not throw
103 
104             assertThrows(UnsupportedOperationException.class, () -> INHERITED_LOCAL2.set(null));
105             assertThrows(UnsupportedOperationException.class, () -> INHERITED_LOCAL2.set(new Object()));
106             assertTrue(INHERITED_LOCAL2.get() == INITIAL_VALUE);
107             INHERITED_LOCAL2.remove();  // should not throw
108         });
109     }
110 
111     /**
112      * Basic test of inheritable thread local set/get, no initial value inherited.
113      */
114     @Test
115     void testInheritedThreadLocal1() throws Exception {
116         assertNull(INHERITED_LOCAL.get());
117         for (int i = 0; i < 10; i++) {
118             VThreadRunner.run(() -> {
119                 assertNull(INHERITED_LOCAL.get());
120                 Object obj = new Object();
121                 INHERITED_LOCAL.set(obj);
122                 assertTrue(INHERITED_LOCAL.get() == obj);
123             });
124         }
125         assertNull(INHERITED_LOCAL.get());
126     }
127 
128     /**
129      * Test inheriting initial value of InheritableThreadLocal from platform thread.
130      */
131     @Test
132     void testInheritedThreadLocal2() throws Exception {
133         assertNull(INHERITED_LOCAL.get());
134         var obj = new Object();
135         INHERITED_LOCAL.set(obj);
136         try {
137             VThreadRunner.run(() -> {
138                 assertTrue(INHERITED_LOCAL.get() == obj);
139             });
140         } finally {
141             INHERITED_LOCAL.remove();
142         }
143     }
144 
145     /**
146      * Test inheriting initial value of InheritableThreadLocal from virtual thread.
147      */
148     @Test
149     void testInheritedThreadLocal3() throws Exception {
150         assertNull(INHERITED_LOCAL.get());
151         VThreadRunner.run(() -> {
152             var obj = new Object();
153             INHERITED_LOCAL.set(obj);
154             VThreadRunner.run(() -> {
155                 assertTrue(INHERITED_LOCAL.get() == obj);
156             });
157             assertTrue(INHERITED_LOCAL.get() == obj);
158 
159         });
160         assertNull(INHERITED_LOCAL.get());
161     }
162 
163     /**
164      * Test Thread that does not inherit initial value of InheritableThreadLocals
165      * from platform thread.
166      */
167     @Test
168     void testInheritedThreadLocal4() throws Exception {
169         assertNull(INHERITED_LOCAL.get());
170         var obj = new Object();
171         INHERITED_LOCAL.set(obj);
172         try {
173             int characteristics = VThreadRunner.NO_INHERIT_THREAD_LOCALS;
174             VThreadRunner.run(characteristics, () -> {
175                 assertNull(INHERITED_LOCAL.get());
176             });
177         } finally {
178             INHERITED_LOCAL.remove();
179         }
180     }
181 
182     /**
183      * Test Thread that does not inherit initial value of InheritableThreadLocals
184      * from virtual thread.
185      */
186     @Test
187     void testInheritedThreadLocal5() throws Exception {
188         assertNull(INHERITED_LOCAL.get());
189         VThreadRunner.run(() -> {
190             var obj = new Object();
191             INHERITED_LOCAL.set(obj);
192             int characteristics = VThreadRunner.NO_INHERIT_THREAD_LOCALS;
193             VThreadRunner.run(characteristics, () -> {
194                 assertNull(INHERITED_LOCAL.get());
195             });
196             assertTrue(INHERITED_LOCAL.get() == obj);
197 
198         });
199         assertNull(INHERITED_LOCAL.get());
200     }
201 }