< prev index next >

src/java.base/share/classes/jdk/internal/vm/SharedThreadContainer.java

Print this page

  1 /*
  2  * Copyright (c) 2021, 2022, 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.vm;
 26 
 27 import java.lang.invoke.MethodHandles;
 28 import java.lang.invoke.VarHandle;
 29 import java.util.Objects;
 30 import java.util.Set;
 31 import java.util.concurrent.ConcurrentHashMap;
 32 import java.util.concurrent.atomic.LongAdder;
 33 import java.util.stream.Stream;
 34 import jdk.internal.access.JavaLangAccess;
 35 import jdk.internal.access.SharedSecrets;
 36 
 37 /**
 38  * A "shared" thread container. A shared thread container doesn't have an owner
 39  * and is intended for unstructured uses, e.g. thread pools.
 40  */
 41 public class SharedThreadContainer extends ThreadContainer implements AutoCloseable {
 42     private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
 43     private static final VarHandle CLOSED;
 44     private static final VarHandle VIRTUAL_THREADS;
 45     static {
 46         try {
 47             MethodHandles.Lookup l = MethodHandles.lookup();
 48             CLOSED = l.findVarHandle(SharedThreadContainer.class,
 49                     "closed", boolean.class);
 50             VIRTUAL_THREADS = l.findVarHandle(SharedThreadContainer.class,
 51                     "virtualThreads", Set.class);
 52         } catch (Exception e) {
 53             throw new InternalError(e);
 54         }
 55     }
 56 
 57     // name of container, used by toString
 58     private final String name;
 59 
 60     // the number of threads in the container
 61     private final LongAdder threadCount;
 62 
 63     // the virtual threads in the container, created lazily
 64     private volatile Set<Thread> virtualThreads;
 65 
 66     // the key for this container in the registry
 67     private volatile Object key;
 68 
 69     // set to true when the container is closed
 70     private volatile boolean closed;
 71 
 72     /**
 73      * Initialize a new SharedThreadContainer.
 74      * @param name the container name, can be null
 75      */
 76     private SharedThreadContainer(String name) {
 77         super(/*shared*/ true);
 78         this.name = name;
 79         this.threadCount = new LongAdder();
 80     }
 81 
 82     /**
 83      * Creates a shared thread container with the given parent and name.
 84      * @throws IllegalArgumentException if the parent has an owner.
 85      */
 86     public static SharedThreadContainer create(ThreadContainer parent, String name) {
 87         if (parent.owner() != null)
 88             throw new IllegalArgumentException("parent has owner");
 89         var container = new SharedThreadContainer(name);
 90         // register the container to allow discovery by serviceability tools
 91         container.key = ThreadContainers.registerContainer(container);
 92         return container;
 93     }
 94 
 95     /**
 96      * Creates a shared thread container with the given name. Its parent will be
 97      * the root thread container.
 98      */
 99     public static SharedThreadContainer create(String name) {
100         return create(ThreadContainers.root(), name);
101     }
102 





103     @Override
104     public Thread owner() {
105         return null;
106     }
107 
108     @Override
109     public void onStart(Thread thread) {
110         // virtual threads needs to be tracked
111         if (thread.isVirtual()) {
112             Set<Thread> vthreads = this.virtualThreads;
113             if (vthreads == null) {
114                 vthreads = ConcurrentHashMap.newKeySet();
115                 if (!VIRTUAL_THREADS.compareAndSet(this, null, vthreads)) {
116                     // lost the race
117                     vthreads = this.virtualThreads;
118                 }
119             }
120             vthreads.add(thread);
121         }
122         threadCount.add(1L);
123     }
124 
125     @Override
126     public void onExit(Thread thread) {
127         threadCount.add(-1L);
128         if (thread.isVirtual())
129             virtualThreads.remove(thread);
130     }
131 
132     @Override
133     public long threadCount() {
134         return threadCount.sum();
135     }
136 
137     @Override
138     public Stream<Thread> threads() {
139         // live platform threads in this container
140         Stream<Thread> platformThreads = Stream.of(JLA.getAllThreads())
141                 .filter(t -> JLA.threadContainer(t) == this);
142         Set<Thread> vthreads = this.virtualThreads;
143         if (vthreads == null) {
144             // live platform threads only, no virtual threads
145             return platformThreads;
146         } else {
147             // all live threads in this container
148             return Stream.concat(platformThreads,
149                                  vthreads.stream().filter(Thread::isAlive));
150         }
151     }
152 
153     /**
154      * Starts a thread in this container.
155      * @throws IllegalStateException if the container is closed
156      */
157     public void start(Thread thread) {
158         if (closed)
159             throw new IllegalStateException();
160         JLA.start(thread, this);
161     }
162 
163     /**
164      * Closes this container. Further attempts to start a thread in this container
165      * throw IllegalStateException. This method has no impact on threads that are
166      * still running or starting around the time that this method is invoked.
167      */
168     @Override
169     public void close() {
170         if (!closed && CLOSED.compareAndSet(this, false, true)) {
171             ThreadContainers.deregisterContainer(key);
172         }
173     }
174 
175     @Override
176     public String toString() {
177         String id = Objects.toIdentityString(this);
178         if (name != null) {
179             return name + "/" + id;
180         } else {
181             return id;
182         }
183     }
184 }

  1 /*
  2  * Copyright (c) 2021, 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.  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.vm;
 26 
 27 import java.lang.invoke.MethodHandles;
 28 import java.lang.invoke.VarHandle;

 29 import java.util.Set;
 30 import java.util.concurrent.ConcurrentHashMap;

 31 import java.util.stream.Stream;
 32 import jdk.internal.access.JavaLangAccess;
 33 import jdk.internal.access.SharedSecrets;
 34 
 35 /**
 36  * A "shared" thread container. A shared thread container doesn't have an owner
 37  * and is intended for unstructured uses, e.g. thread pools.
 38  */
 39 public class SharedThreadContainer extends ThreadContainer implements AutoCloseable {
 40     private static final JavaLangAccess JLA = SharedSecrets.getJavaLangAccess();
 41     private static final VarHandle CLOSED;
 42     private static final VarHandle VIRTUAL_THREADS;
 43     static {
 44         try {
 45             MethodHandles.Lookup l = MethodHandles.lookup();
 46             CLOSED = l.findVarHandle(SharedThreadContainer.class,
 47                     "closed", boolean.class);
 48             VIRTUAL_THREADS = l.findVarHandle(SharedThreadContainer.class,
 49                     "virtualThreads", Set.class);
 50         } catch (Exception e) {
 51             throw new ExceptionInInitializerError(e);
 52         }
 53     }
 54 
 55     // name of container, used by toString
 56     private final String name;
 57 



 58     // the virtual threads in the container, created lazily
 59     private volatile Set<Thread> virtualThreads;
 60 
 61     // the key for this container in the registry
 62     private volatile Object key;
 63 
 64     // set to true when the container is closed
 65     private volatile boolean closed;
 66 
 67     /**
 68      * Initialize a new SharedThreadContainer.
 69      * @param name the container name, can be null
 70      */
 71     private SharedThreadContainer(String name) {
 72         super(/*shared*/ true);
 73         this.name = name;

 74     }
 75 
 76     /**
 77      * Creates a shared thread container with the given parent and name.
 78      * @throws IllegalArgumentException if the parent has an owner.
 79      */
 80     public static SharedThreadContainer create(ThreadContainer parent, String name) {
 81         if (parent.owner() != null)
 82             throw new IllegalArgumentException("parent has owner");
 83         var container = new SharedThreadContainer(name);
 84         // register the container to allow discovery by serviceability tools
 85         container.key = ThreadContainers.registerContainer(container);
 86         return container;
 87     }
 88 
 89     /**
 90      * Creates a shared thread container with the given name. Its parent will be
 91      * the root thread container.
 92      */
 93     public static SharedThreadContainer create(String name) {
 94         return create(ThreadContainers.root(), name);
 95     }
 96 
 97     @Override
 98     public String name() {
 99         return name;
100     }
101 
102     @Override
103     public Thread owner() {
104         return null;
105     }
106 
107     @Override
108     public void onStart(Thread thread) {
109         // virtual threads needs to be tracked
110         if (thread.isVirtual()) {
111             Set<Thread> vthreads = this.virtualThreads;
112             if (vthreads == null) {
113                 vthreads = ConcurrentHashMap.newKeySet();
114                 if (!VIRTUAL_THREADS.compareAndSet(this, null, vthreads)) {
115                     // lost the race
116                     vthreads = this.virtualThreads;
117                 }
118             }
119             vthreads.add(thread);
120         }

121     }
122 
123     @Override
124     public void onExit(Thread thread) {

125         if (thread.isVirtual())
126             virtualThreads.remove(thread);
127     }
128 





129     @Override
130     public Stream<Thread> threads() {
131         // live platform threads in this container
132         Stream<Thread> platformThreads = Stream.of(JLA.getAllThreads())
133                 .filter(t -> JLA.threadContainer(t) == this);
134         Set<Thread> vthreads = this.virtualThreads;
135         if (vthreads == null) {
136             // live platform threads only, no virtual threads
137             return platformThreads;
138         } else {
139             // all live threads in this container
140             return Stream.concat(platformThreads,
141                                  vthreads.stream().filter(Thread::isAlive));
142         }
143     }
144 
145     /**
146      * Starts a thread in this container.
147      * @throws IllegalStateException if the container is closed
148      */
149     public void start(Thread thread) {
150         if (closed)
151             throw new IllegalStateException();
152         JLA.start(thread, this);
153     }
154 
155     /**
156      * Closes this container. Further attempts to start a thread in this container
157      * throw IllegalStateException. This method has no impact on threads that are
158      * still running or starting around the time that this method is invoked.
159      */
160     @Override
161     public void close() {
162         if (!closed && CLOSED.compareAndSet(this, false, true)) {
163             ThreadContainers.deregisterContainer(key);
164         }
165     }










166 }
< prev index next >