1 /*
  2  * Copyright (c) 2018, 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.  Oracle designates this
  8  * particular file as subject to the "Classpath" exception as provided
  9  * by Oracle in the LICENSE file that accompanied this code.
 10  *
 11  * This code is distributed in the hope that it will be useful, but WITHOUT
 12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 14  * version 2 for more details (a copy is included in the LICENSE file that
 15  * accompanied this code).
 16  *
 17  * You should have received a copy of the GNU General Public License version
 18  * 2 along with this work; if not, write to the Free Software Foundation,
 19  * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
 20  *
 21  * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
 22  * or visit www.oracle.com if you need additional information or have any
 23  * questions.
 24  */
 25 package jdk.internal.misc;
 26 
 27 import java.util.Collection;
 28 import java.util.Collections;
 29 import java.util.IdentityHashMap;
 30 
 31 /**
 32  * A thread-local variable that is notified when a thread terminates and
 33  * it has been initialized in the terminating thread (even if it was
 34  * initialized with a null value).
 35  */
 36 public class TerminatingThreadLocal<T> extends ThreadLocal<T> {
 37 
 38     @Override
 39     public void set(T value) {
 40         super.set(value);
 41         register(this);
 42     }
 43 
 44     @Override
 45     public void remove() {
 46         super.remove();
 47         unregister(this);
 48     }
 49 
 50     /**
 51      * Invoked by a thread when terminating and this thread-local has an associated
 52      * value for the terminating thread (even if that value is null), so that any
 53      * native resources maintained by the value can be released.
 54      *
 55      * @param value current thread's value of this thread-local variable
 56      *              (may be null but only if null value was explicitly initialized)
 57      */
 58     protected void threadTerminated(T value) {
 59     }
 60 
 61     // following methods and field are implementation details and should only be
 62     // called from the corresponding code int Thread/ThreadLocal class.
 63 
 64     /**
 65      * Invokes the TerminatingThreadLocal's {@link #threadTerminated()} method
 66      * on all instances registered in current thread.
 67      */
 68     public static void threadTerminated() {
 69         for (TerminatingThreadLocal<?> ttl : REGISTRY.get()) {
 70             ttl._threadTerminated();
 71         }
 72     }
 73 
 74     private void _threadTerminated() { threadTerminated(get()); }
 75 
 76     /**
 77      * Register given TerminatingThreadLocal
 78      *
 79      * @param tl the ThreadLocal to register
 80      */
 81     public static void register(TerminatingThreadLocal<?> tl) {
 82         if (!Thread.currentThread().isVirtual())
 83             REGISTRY.get().add(tl);
 84     }
 85 
 86     /**
 87      * Unregister given TerminatingThreadLocal
 88      *
 89      * @param tl the ThreadLocal to unregister
 90      */
 91     private static void unregister(TerminatingThreadLocal<?> tl) {
 92         if (!Thread.currentThread().isVirtual())
 93             REGISTRY.get().remove(tl);
 94     }
 95 
 96     /**
 97      * a per-thread registry of TerminatingThreadLocal(s) that have been registered
 98      * but later not unregistered in a particular thread.
 99      */
100     public static final ThreadLocal<Collection<TerminatingThreadLocal<?>>> REGISTRY =
101         new ThreadLocal<>() {
102             @Override
103             protected Collection<TerminatingThreadLocal<?>> initialValue() {
104                 return Collections.newSetFromMap(new IdentityHashMap<>(4));
105             }
106         };
107 }
--- EOF ---