Print this page
Split |
Close |
Expand all |
Collapse all |
--- old/src/share/classes/java/lang/ThreadGroup.java
+++ new/src/share/classes/java/lang/ThreadGroup.java
1 1 /*
2 2 * Copyright (c) 1995, 2007, Oracle and/or its affiliates. All rights reserved.
3 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 4 *
5 5 * This code is free software; you can redistribute it and/or modify it
6 6 * under the terms of the GNU General Public License version 2 only, as
7 7 * published by the Free Software Foundation. Oracle designates this
8 8 * particular file as subject to the "Classpath" exception as provided
9 9 * by Oracle in the LICENSE file that accompanied this code.
10 10 *
11 11 * This code is distributed in the hope that it will be useful, but WITHOUT
12 12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 14 * version 2 for more details (a copy is included in the LICENSE file that
15 15 * accompanied this code).
16 16 *
17 17 * You should have received a copy of the GNU General Public License version
18 18 * 2 along with this work; if not, write to the Free Software Foundation,
19 19 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 20 *
21 21 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 22 * or visit www.oracle.com if you need additional information or have any
23 23 * questions.
24 24 */
25 25
26 26 package java.lang;
27 27
28 28 import java.io.PrintStream;
29 29 import java.util.Arrays;
30 30 import sun.misc.VM;
31 31
32 32 /**
33 33 * A thread group represents a set of threads. In addition, a thread
34 34 * group can also include other thread groups. The thread groups form
35 35 * a tree in which every thread group except the initial thread group
36 36 * has a parent.
37 37 * <p>
38 38 * A thread is allowed to access information about its own thread
39 39 * group, but not to access information about its thread group's
40 40 * parent thread group or any other thread groups.
41 41 *
42 42 * @author unascribed
43 43 * @since JDK1.0
44 44 */
45 45 /* The locking strategy for this code is to try to lock only one level of the
46 46 * tree wherever possible, but otherwise to lock from the bottom up.
47 47 * That is, from child thread groups to parents.
48 48 * This has the advantage of limiting the number of locks that need to be held
49 49 * and in particular avoids having to grab the lock for the root thread group,
50 50 * (or a global lock) which would be a source of contention on a
51 51 * multi-processor system with many thread groups.
52 52 * This policy often leads to taking a snapshot of the state of a thread group
53 53 * and working off of that snapshot, rather than holding the thread group locked
54 54 * while we work on the children.
55 55 */
56 56 public
57 57 class ThreadGroup implements Thread.UncaughtExceptionHandler {
58 58 private final ThreadGroup parent;
59 59 String name;
60 60 int maxPriority;
61 61 boolean destroyed;
62 62 boolean daemon;
63 63 boolean vmAllowSuspension;
64 64
65 65 int nUnstartedThreads = 0;
66 66 int nthreads;
67 67 Thread threads[];
68 68
69 69 int ngroups;
70 70 ThreadGroup groups[];
71 71
72 72 /**
73 73 * Creates an empty Thread group that is not in any Thread group.
74 74 * This method is used to create the system Thread group.
75 75 */
76 76 private ThreadGroup() { // called from C code
77 77 this.name = "system";
78 78 this.maxPriority = Thread.MAX_PRIORITY;
79 79 this.parent = null;
80 80 }
81 81
82 82 /**
83 83 * Constructs a new thread group. The parent of this new group is
84 84 * the thread group of the currently running thread.
85 85 * <p>
86 86 * The <code>checkAccess</code> method of the parent thread group is
87 87 * called with no arguments; this may result in a security exception.
88 88 *
89 89 * @param name the name of the new thread group.
90 90 * @exception SecurityException if the current thread cannot create a
91 91 * thread in the specified thread group.
92 92 * @see java.lang.ThreadGroup#checkAccess()
93 93 * @since JDK1.0
94 94 */
95 95 public ThreadGroup(String name) {
96 96 this(Thread.currentThread().getThreadGroup(), name);
97 97 }
98 98
99 99 /**
100 100 * Creates a new thread group. The parent of this new group is the
101 101 * specified thread group.
102 102 * <p>
103 103 * The <code>checkAccess</code> method of the parent thread group is
104 104 * called with no arguments; this may result in a security exception.
105 105 *
106 106 * @param parent the parent thread group.
107 107 * @param name the name of the new thread group.
108 108 * @exception NullPointerException if the thread group argument is
109 109 * <code>null</code>.
110 110 * @exception SecurityException if the current thread cannot create a
111 111 * thread in the specified thread group.
112 112 * @see java.lang.SecurityException
113 113 * @see java.lang.ThreadGroup#checkAccess()
114 114 * @since JDK1.0
115 115 */
116 116 public ThreadGroup(ThreadGroup parent, String name) {
117 117 this(checkParentAccess(parent), parent, name);
118 118 }
119 119
120 120 private ThreadGroup(Void unused, ThreadGroup parent, String name) {
121 121 this.name = name;
122 122 this.maxPriority = parent.maxPriority;
123 123 this.daemon = parent.daemon;
124 124 this.vmAllowSuspension = parent.vmAllowSuspension;
125 125 this.parent = parent;
126 126 parent.add(this);
127 127 }
128 128
129 129 /*
130 130 * @throws NullPointerException if the parent argument is {@code null}
131 131 * @throws SecurityException if the current thread cannot create a
132 132 * thread in the specified thread group.
133 133 */
134 134 private static Void checkParentAccess(ThreadGroup parent) {
135 135 parent.checkAccess();
136 136 return null;
137 137 }
138 138
139 139 /**
140 140 * Returns the name of this thread group.
141 141 *
142 142 * @return the name of this thread group.
143 143 * @since JDK1.0
144 144 */
145 145 public final String getName() {
146 146 return name;
147 147 }
148 148
149 149 /**
150 150 * Returns the parent of this thread group.
151 151 * <p>
152 152 * First, if the parent is not <code>null</code>, the
153 153 * <code>checkAccess</code> method of the parent thread group is
154 154 * called with no arguments; this may result in a security exception.
155 155 *
156 156 * @return the parent of this thread group. The top-level thread group
157 157 * is the only thread group whose parent is <code>null</code>.
158 158 * @exception SecurityException if the current thread cannot modify
159 159 * this thread group.
160 160 * @see java.lang.ThreadGroup#checkAccess()
161 161 * @see java.lang.SecurityException
162 162 * @see java.lang.RuntimePermission
163 163 * @since JDK1.0
164 164 */
165 165 public final ThreadGroup getParent() {
166 166 if (parent != null)
167 167 parent.checkAccess();
168 168 return parent;
169 169 }
170 170
171 171 /**
172 172 * Returns the maximum priority of this thread group. Threads that are
173 173 * part of this group cannot have a higher priority than the maximum
174 174 * priority.
175 175 *
176 176 * @return the maximum priority that a thread in this thread group
177 177 * can have.
178 178 * @see #setMaxPriority
179 179 * @since JDK1.0
180 180 */
181 181 public final int getMaxPriority() {
182 182 return maxPriority;
183 183 }
184 184
185 185 /**
186 186 * Tests if this thread group is a daemon thread group. A
187 187 * daemon thread group is automatically destroyed when its last
188 188 * thread is stopped or its last thread group is destroyed.
189 189 *
190 190 * @return <code>true</code> if this thread group is a daemon thread group;
191 191 * <code>false</code> otherwise.
192 192 * @since JDK1.0
193 193 */
194 194 public final boolean isDaemon() {
195 195 return daemon;
196 196 }
197 197
198 198 /**
199 199 * Tests if this thread group has been destroyed.
200 200 *
201 201 * @return true if this object is destroyed
202 202 * @since JDK1.1
203 203 */
204 204 public synchronized boolean isDestroyed() {
205 205 return destroyed;
206 206 }
207 207
208 208 /**
209 209 * Changes the daemon status of this thread group.
210 210 * <p>
211 211 * First, the <code>checkAccess</code> method of this thread group is
212 212 * called with no arguments; this may result in a security exception.
213 213 * <p>
214 214 * A daemon thread group is automatically destroyed when its last
215 215 * thread is stopped or its last thread group is destroyed.
216 216 *
217 217 * @param daemon if <code>true</code>, marks this thread group as
218 218 * a daemon thread group; otherwise, marks this
219 219 * thread group as normal.
220 220 * @exception SecurityException if the current thread cannot modify
221 221 * this thread group.
222 222 * @see java.lang.SecurityException
223 223 * @see java.lang.ThreadGroup#checkAccess()
224 224 * @since JDK1.0
225 225 */
226 226 public final void setDaemon(boolean daemon) {
227 227 checkAccess();
228 228 this.daemon = daemon;
229 229 }
230 230
231 231 /**
232 232 * Sets the maximum priority of the group. Threads in the thread
233 233 * group that already have a higher priority are not affected.
234 234 * <p>
235 235 * First, the <code>checkAccess</code> method of this thread group is
236 236 * called with no arguments; this may result in a security exception.
237 237 * <p>
238 238 * If the <code>pri</code> argument is less than
239 239 * {@link Thread#MIN_PRIORITY} or greater than
240 240 * {@link Thread#MAX_PRIORITY}, the maximum priority of the group
241 241 * remains unchanged.
242 242 * <p>
243 243 * Otherwise, the priority of this ThreadGroup object is set to the
244 244 * smaller of the specified <code>pri</code> and the maximum permitted
245 245 * priority of the parent of this thread group. (If this thread group
246 246 * is the system thread group, which has no parent, then its maximum
247 247 * priority is simply set to <code>pri</code>.) Then this method is
248 248 * called recursively, with <code>pri</code> as its argument, for
249 249 * every thread group that belongs to this thread group.
250 250 *
251 251 * @param pri the new priority of the thread group.
252 252 * @exception SecurityException if the current thread cannot modify
253 253 * this thread group.
254 254 * @see #getMaxPriority
255 255 * @see java.lang.SecurityException
256 256 * @see java.lang.ThreadGroup#checkAccess()
257 257 * @since JDK1.0
258 258 */
259 259 public final void setMaxPriority(int pri) {
260 260 int ngroupsSnapshot;
261 261 ThreadGroup[] groupsSnapshot;
262 262 synchronized (this) {
263 263 checkAccess();
264 264 if (pri < Thread.MIN_PRIORITY || pri > Thread.MAX_PRIORITY) {
265 265 return;
266 266 }
267 267 maxPriority = (parent != null) ? Math.min(pri, parent.maxPriority) : pri;
268 268 ngroupsSnapshot = ngroups;
269 269 if (groups != null) {
270 270 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
271 271 } else {
272 272 groupsSnapshot = null;
273 273 }
274 274 }
275 275 for (int i = 0 ; i < ngroupsSnapshot ; i++) {
276 276 groupsSnapshot[i].setMaxPriority(pri);
277 277 }
278 278 }
279 279
280 280 /**
281 281 * Tests if this thread group is either the thread group
282 282 * argument or one of its ancestor thread groups.
283 283 *
284 284 * @param g a thread group.
285 285 * @return <code>true</code> if this thread group is the thread group
286 286 * argument or one of its ancestor thread groups;
287 287 * <code>false</code> otherwise.
288 288 * @since JDK1.0
289 289 */
290 290 public final boolean parentOf(ThreadGroup g) {
291 291 for (; g != null ; g = g.parent) {
292 292 if (g == this) {
293 293 return true;
294 294 }
295 295 }
296 296 return false;
297 297 }
298 298
299 299 /**
300 300 * Determines if the currently running thread has permission to
301 301 * modify this thread group.
302 302 * <p>
303 303 * If there is a security manager, its <code>checkAccess</code> method
304 304 * is called with this thread group as its argument. This may result
305 305 * in throwing a <code>SecurityException</code>.
306 306 *
307 307 * @exception SecurityException if the current thread is not allowed to
308 308 * access this thread group.
309 309 * @see java.lang.SecurityManager#checkAccess(java.lang.ThreadGroup)
310 310 * @since JDK1.0
311 311 */
312 312 public final void checkAccess() {
313 313 SecurityManager security = System.getSecurityManager();
314 314 if (security != null) {
315 315 security.checkAccess(this);
316 316 }
317 317 }
318 318
319 319 /**
320 320 * Returns an estimate of the number of active threads in this thread
321 321 * group and its subgroups. Recursively iterates over all subgroups in
322 322 * this thread group.
323 323 *
324 324 * <p> The value returned is only an estimate because the number of
325 325 * threads may change dynamically while this method traverses internal
326 326 * data structures, and might be affected by the presence of certain
327 327 * system threads. This method is intended primarily for debugging
328 328 * and monitoring purposes.
329 329 *
330 330 * @return an estimate of the number of active threads in this thread
331 331 * group and in any other thread group that has this thread
332 332 * group as an ancestor
333 333 *
334 334 * @since JDK1.0
335 335 */
336 336 public int activeCount() {
337 337 int result;
338 338 // Snapshot sub-group data so we don't hold this lock
339 339 // while our children are computing.
340 340 int ngroupsSnapshot;
341 341 ThreadGroup[] groupsSnapshot;
342 342 synchronized (this) {
343 343 if (destroyed) {
344 344 return 0;
345 345 }
346 346 result = nthreads;
347 347 ngroupsSnapshot = ngroups;
348 348 if (groups != null) {
349 349 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
350 350 } else {
351 351 groupsSnapshot = null;
352 352 }
353 353 }
354 354 for (int i = 0 ; i < ngroupsSnapshot ; i++) {
355 355 result += groupsSnapshot[i].activeCount();
356 356 }
357 357 return result;
358 358 }
359 359
360 360 /**
361 361 * Copies into the specified array every active thread in this
362 362 * thread group and its subgroups.
363 363 *
364 364 * <p> An invocation of this method behaves in exactly the same
365 365 * way as the invocation
366 366 *
367 367 * <blockquote>
368 368 * {@linkplain #enumerate(Thread[], boolean) enumerate}{@code (list, true)}
369 369 * </blockquote>
370 370 *
371 371 * @param list
372 372 * an array into which to put the list of threads
373 373 *
374 374 * @return the number of threads put into the array
375 375 *
376 376 * @throws SecurityException
377 377 * if {@linkplain #checkAccess checkAccess} determines that
378 378 * the current thread cannot access this thread group
379 379 *
380 380 * @since JDK1.0
381 381 */
382 382 public int enumerate(Thread list[]) {
383 383 checkAccess();
384 384 return enumerate(list, 0, true);
385 385 }
386 386
387 387 /**
388 388 * Copies into the specified array every active thread in this
389 389 * thread group. If {@code recurse} is {@code true},
390 390 * this method recursively enumerates all subgroups of this
391 391 * thread group and references to every active thread in these
392 392 * subgroups are also included. If the array is too short to
393 393 * hold all the threads, the extra threads are silently ignored.
394 394 *
395 395 * <p> An application might use the {@linkplain #activeCount activeCount}
396 396 * method to get an estimate of how big the array should be, however
397 397 * <i>if the array is too short to hold all the threads, the extra threads
398 398 * are silently ignored.</i> If it is critical to obtain every active
399 399 * thread in this thread group, the caller should verify that the returned
400 400 * int value is strictly less than the length of {@code list}.
401 401 *
402 402 * <p> Due to the inherent race condition in this method, it is recommended
403 403 * that the method only be used for debugging and monitoring purposes.
404 404 *
405 405 * @param list
406 406 * an array into which to put the list of threads
407 407 *
408 408 * @param recurse
409 409 * if {@code true}, recursively enumerate all subgroups of this
410 410 * thread group
411 411 *
412 412 * @return the number of threads put into the array
413 413 *
414 414 * @throws SecurityException
415 415 * if {@linkplain #checkAccess checkAccess} determines that
416 416 * the current thread cannot access this thread group
417 417 *
418 418 * @since JDK1.0
419 419 */
420 420 public int enumerate(Thread list[], boolean recurse) {
421 421 checkAccess();
422 422 return enumerate(list, 0, recurse);
423 423 }
424 424
425 425 private int enumerate(Thread list[], int n, boolean recurse) {
426 426 int ngroupsSnapshot = 0;
427 427 ThreadGroup[] groupsSnapshot = null;
428 428 synchronized (this) {
429 429 if (destroyed) {
430 430 return 0;
431 431 }
432 432 int nt = nthreads;
433 433 if (nt > list.length - n) {
434 434 nt = list.length - n;
435 435 }
436 436 for (int i = 0; i < nt; i++) {
437 437 if (threads[i].isAlive()) {
438 438 list[n++] = threads[i];
439 439 }
440 440 }
441 441 if (recurse) {
442 442 ngroupsSnapshot = ngroups;
443 443 if (groups != null) {
444 444 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
445 445 } else {
446 446 groupsSnapshot = null;
447 447 }
448 448 }
449 449 }
450 450 if (recurse) {
451 451 for (int i = 0 ; i < ngroupsSnapshot ; i++) {
452 452 n = groupsSnapshot[i].enumerate(list, n, true);
453 453 }
454 454 }
455 455 return n;
456 456 }
457 457
458 458 /**
459 459 * Returns an estimate of the number of active groups in this
460 460 * thread group and its subgroups. Recursively iterates over
461 461 * all subgroups in this thread group.
462 462 *
463 463 * <p> The value returned is only an estimate because the number of
464 464 * thread groups may change dynamically while this method traverses
465 465 * internal data structures. This method is intended primarily for
466 466 * debugging and monitoring purposes.
467 467 *
468 468 * @return the number of active thread groups with this thread group as
469 469 * an ancestor
470 470 *
471 471 * @since JDK1.0
472 472 */
473 473 public int activeGroupCount() {
474 474 int ngroupsSnapshot;
475 475 ThreadGroup[] groupsSnapshot;
476 476 synchronized (this) {
477 477 if (destroyed) {
478 478 return 0;
479 479 }
480 480 ngroupsSnapshot = ngroups;
481 481 if (groups != null) {
482 482 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
483 483 } else {
484 484 groupsSnapshot = null;
485 485 }
486 486 }
487 487 int n = ngroupsSnapshot;
488 488 for (int i = 0 ; i < ngroupsSnapshot ; i++) {
489 489 n += groupsSnapshot[i].activeGroupCount();
490 490 }
491 491 return n;
492 492 }
493 493
494 494 /**
495 495 * Copies into the specified array references to every active
496 496 * subgroup in this thread group and its subgroups.
497 497 *
498 498 * <p> An invocation of this method behaves in exactly the same
499 499 * way as the invocation
500 500 *
501 501 * <blockquote>
502 502 * {@linkplain #enumerate(ThreadGroup[], boolean) enumerate}{@code (list, true)}
503 503 * </blockquote>
504 504 *
505 505 * @param list
506 506 * an array into which to put the list of thread groups
507 507 *
508 508 * @return the number of thread groups put into the array
509 509 *
510 510 * @throws SecurityException
511 511 * if {@linkplain #checkAccess checkAccess} determines that
512 512 * the current thread cannot access this thread group
513 513 *
514 514 * @since JDK1.0
515 515 */
516 516 public int enumerate(ThreadGroup list[]) {
517 517 checkAccess();
518 518 return enumerate(list, 0, true);
519 519 }
520 520
521 521 /**
522 522 * Copies into the specified array references to every active
523 523 * subgroup in this thread group. If {@code recurse} is
524 524 * {@code true}, this method recursively enumerates all subgroups of this
525 525 * thread group and references to every active thread group in these
526 526 * subgroups are also included.
527 527 *
528 528 * <p> An application might use the
529 529 * {@linkplain #activeGroupCount activeGroupCount} method to
530 530 * get an estimate of how big the array should be, however <i>if the
531 531 * array is too short to hold all the thread groups, the extra thread
532 532 * groups are silently ignored.</i> If it is critical to obtain every
533 533 * active subgroup in this thread group, the caller should verify that
534 534 * the returned int value is strictly less than the length of
535 535 * {@code list}.
536 536 *
537 537 * <p> Due to the inherent race condition in this method, it is recommended
538 538 * that the method only be used for debugging and monitoring purposes.
539 539 *
540 540 * @param list
541 541 * an array into which to put the list of thread groups
542 542 *
543 543 * @param recurse
544 544 * if {@code true}, recursively enumerate all subgroups
545 545 *
546 546 * @return the number of thread groups put into the array
547 547 *
548 548 * @throws SecurityException
549 549 * if {@linkplain #checkAccess checkAccess} determines that
550 550 * the current thread cannot access this thread group
551 551 *
552 552 * @since JDK1.0
553 553 */
554 554 public int enumerate(ThreadGroup list[], boolean recurse) {
555 555 checkAccess();
556 556 return enumerate(list, 0, recurse);
557 557 }
558 558
559 559 private int enumerate(ThreadGroup list[], int n, boolean recurse) {
560 560 int ngroupsSnapshot = 0;
561 561 ThreadGroup[] groupsSnapshot = null;
562 562 synchronized (this) {
563 563 if (destroyed) {
564 564 return 0;
565 565 }
566 566 int ng = ngroups;
567 567 if (ng > list.length - n) {
568 568 ng = list.length - n;
569 569 }
570 570 if (ng > 0) {
571 571 System.arraycopy(groups, 0, list, n, ng);
572 572 n += ng;
573 573 }
574 574 if (recurse) {
575 575 ngroupsSnapshot = ngroups;
576 576 if (groups != null) {
577 577 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
578 578 } else {
579 579 groupsSnapshot = null;
580 580 }
581 581 }
582 582 }
583 583 if (recurse) {
584 584 for (int i = 0 ; i < ngroupsSnapshot ; i++) {
585 585 n = groupsSnapshot[i].enumerate(list, n, true);
586 586 }
587 587 }
588 588 return n;
589 589 }
590 590
591 591 /**
592 592 * Stops all threads in this thread group.
593 593 * <p>
594 594 * First, the <code>checkAccess</code> method of this thread group is
595 595 * called with no arguments; this may result in a security exception.
596 596 * <p>
597 597 * This method then calls the <code>stop</code> method on all the
598 598 * threads in this thread group and in all of its subgroups.
599 599 *
600 600 * @exception SecurityException if the current thread is not allowed
601 601 * to access this thread group or any of the threads in
602 602 * the thread group.
603 603 * @see java.lang.SecurityException
604 604 * @see java.lang.Thread#stop()
605 605 * @see java.lang.ThreadGroup#checkAccess()
606 606 * @since JDK1.0
607 607 * @deprecated This method is inherently unsafe. See
608 608 * {@link Thread#stop} for details.
609 609 */
610 610 @Deprecated
611 611 public final void stop() {
612 612 if (stopOrSuspend(false))
613 613 Thread.currentThread().stop();
614 614 }
615 615
616 616 /**
617 617 * Interrupts all threads in this thread group.
618 618 * <p>
619 619 * First, the <code>checkAccess</code> method of this thread group is
620 620 * called with no arguments; this may result in a security exception.
621 621 * <p>
622 622 * This method then calls the <code>interrupt</code> method on all the
623 623 * threads in this thread group and in all of its subgroups.
624 624 *
625 625 * @exception SecurityException if the current thread is not allowed
626 626 * to access this thread group or any of the threads in
627 627 * the thread group.
628 628 * @see java.lang.Thread#interrupt()
629 629 * @see java.lang.SecurityException
630 630 * @see java.lang.ThreadGroup#checkAccess()
631 631 * @since 1.2
632 632 */
633 633 public final void interrupt() {
634 634 int ngroupsSnapshot;
635 635 ThreadGroup[] groupsSnapshot;
636 636 synchronized (this) {
637 637 checkAccess();
638 638 for (int i = 0 ; i < nthreads ; i++) {
639 639 threads[i].interrupt();
640 640 }
641 641 ngroupsSnapshot = ngroups;
642 642 if (groups != null) {
643 643 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
644 644 } else {
645 645 groupsSnapshot = null;
646 646 }
647 647 }
648 648 for (int i = 0 ; i < ngroupsSnapshot ; i++) {
649 649 groupsSnapshot[i].interrupt();
650 650 }
651 651 }
652 652
653 653 /**
654 654 * Suspends all threads in this thread group.
655 655 * <p>
656 656 * First, the <code>checkAccess</code> method of this thread group is
657 657 * called with no arguments; this may result in a security exception.
658 658 * <p>
659 659 * This method then calls the <code>suspend</code> method on all the
660 660 * threads in this thread group and in all of its subgroups.
661 661 *
662 662 * @exception SecurityException if the current thread is not allowed
663 663 * to access this thread group or any of the threads in
664 664 * the thread group.
665 665 * @see java.lang.Thread#suspend()
666 666 * @see java.lang.SecurityException
667 667 * @see java.lang.ThreadGroup#checkAccess()
668 668 * @since JDK1.0
669 669 * @deprecated This method is inherently deadlock-prone. See
670 670 * {@link Thread#suspend} for details.
671 671 */
672 672 @Deprecated
673 673 public final void suspend() {
674 674 if (stopOrSuspend(true))
675 675 Thread.currentThread().suspend();
676 676 }
677 677
678 678 /**
679 679 * Helper method: recursively stops or suspends (as directed by the
680 680 * boolean argument) all of the threads in this thread group and its
681 681 * subgroups, except the current thread. This method returns true
682 682 * if (and only if) the current thread is found to be in this thread
683 683 * group or one of its subgroups.
684 684 */
685 685 private boolean stopOrSuspend(boolean suspend) {
686 686 boolean suicide = false;
687 687 Thread us = Thread.currentThread();
688 688 int ngroupsSnapshot;
689 689 ThreadGroup[] groupsSnapshot = null;
690 690 synchronized (this) {
691 691 checkAccess();
692 692 for (int i = 0 ; i < nthreads ; i++) {
693 693 if (threads[i]==us)
694 694 suicide = true;
695 695 else if (suspend)
696 696 threads[i].suspend();
697 697 else
698 698 threads[i].stop();
699 699 }
700 700
701 701 ngroupsSnapshot = ngroups;
702 702 if (groups != null) {
703 703 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
704 704 }
705 705 }
706 706 for (int i = 0 ; i < ngroupsSnapshot ; i++)
707 707 suicide = groupsSnapshot[i].stopOrSuspend(suspend) || suicide;
708 708
709 709 return suicide;
710 710 }
711 711
712 712 /**
713 713 * Resumes all threads in this thread group.
714 714 * <p>
715 715 * First, the <code>checkAccess</code> method of this thread group is
716 716 * called with no arguments; this may result in a security exception.
717 717 * <p>
718 718 * This method then calls the <code>resume</code> method on all the
719 719 * threads in this thread group and in all of its sub groups.
720 720 *
721 721 * @exception SecurityException if the current thread is not allowed to
722 722 * access this thread group or any of the threads in the
723 723 * thread group.
724 724 * @see java.lang.SecurityException
725 725 * @see java.lang.Thread#resume()
726 726 * @see java.lang.ThreadGroup#checkAccess()
727 727 * @since JDK1.0
728 728 * @deprecated This method is used solely in conjunction with
729 729 * <tt>Thread.suspend</tt> and <tt>ThreadGroup.suspend</tt>,
730 730 * both of which have been deprecated, as they are inherently
731 731 * deadlock-prone. See {@link Thread#suspend} for details.
732 732 */
733 733 @Deprecated
734 734 public final void resume() {
735 735 int ngroupsSnapshot;
736 736 ThreadGroup[] groupsSnapshot;
737 737 synchronized (this) {
738 738 checkAccess();
739 739 for (int i = 0 ; i < nthreads ; i++) {
740 740 threads[i].resume();
741 741 }
742 742 ngroupsSnapshot = ngroups;
743 743 if (groups != null) {
744 744 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
745 745 } else {
746 746 groupsSnapshot = null;
747 747 }
748 748 }
749 749 for (int i = 0 ; i < ngroupsSnapshot ; i++) {
750 750 groupsSnapshot[i].resume();
751 751 }
752 752 }
753 753
754 754 /**
755 755 * Destroys this thread group and all of its subgroups. This thread
756 756 * group must be empty, indicating that all threads that had been in
757 757 * this thread group have since stopped.
758 758 * <p>
759 759 * First, the <code>checkAccess</code> method of this thread group is
760 760 * called with no arguments; this may result in a security exception.
761 761 *
762 762 * @exception IllegalThreadStateException if the thread group is not
763 763 * empty or if the thread group has already been destroyed.
764 764 * @exception SecurityException if the current thread cannot modify this
765 765 * thread group.
766 766 * @see java.lang.ThreadGroup#checkAccess()
767 767 * @since JDK1.0
768 768 */
769 769 public final void destroy() {
770 770 int ngroupsSnapshot;
771 771 ThreadGroup[] groupsSnapshot;
772 772 synchronized (this) {
773 773 checkAccess();
774 774 if (destroyed || (nthreads > 0)) {
775 775 throw new IllegalThreadStateException();
776 776 }
777 777 ngroupsSnapshot = ngroups;
778 778 if (groups != null) {
779 779 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
780 780 } else {
781 781 groupsSnapshot = null;
782 782 }
783 783 if (parent != null) {
784 784 destroyed = true;
785 785 ngroups = 0;
786 786 groups = null;
787 787 nthreads = 0;
788 788 threads = null;
789 789 }
790 790 }
791 791 for (int i = 0 ; i < ngroupsSnapshot ; i += 1) {
792 792 groupsSnapshot[i].destroy();
793 793 }
794 794 if (parent != null) {
795 795 parent.remove(this);
796 796 }
797 797 }
798 798
799 799 /**
800 800 * Adds the specified Thread group to this group.
801 801 * @param g the specified Thread group to be added
802 802 * @exception IllegalThreadStateException If the Thread group has been destroyed.
803 803 */
804 804 private final void add(ThreadGroup g){
805 805 synchronized (this) {
806 806 if (destroyed) {
807 807 throw new IllegalThreadStateException();
808 808 }
809 809 if (groups == null) {
810 810 groups = new ThreadGroup[4];
811 811 } else if (ngroups == groups.length) {
812 812 groups = Arrays.copyOf(groups, ngroups * 2);
813 813 }
814 814 groups[ngroups] = g;
815 815
816 816 // This is done last so it doesn't matter in case the
817 817 // thread is killed
818 818 ngroups++;
819 819 }
820 820 }
821 821
822 822 /**
823 823 * Removes the specified Thread group from this group.
824 824 * @param g the Thread group to be removed
825 825 * @return if this Thread has already been destroyed.
826 826 */
827 827 private void remove(ThreadGroup g) {
828 828 synchronized (this) {
829 829 if (destroyed) {
830 830 return;
831 831 }
832 832 for (int i = 0 ; i < ngroups ; i++) {
833 833 if (groups[i] == g) {
834 834 ngroups -= 1;
835 835 System.arraycopy(groups, i + 1, groups, i, ngroups - i);
836 836 // Zap dangling reference to the dead group so that
837 837 // the garbage collector will collect it.
838 838 groups[ngroups] = null;
839 839 break;
840 840 }
841 841 }
842 842 if (nthreads == 0) {
843 843 notifyAll();
844 844 }
845 845 if (daemon && (nthreads == 0) &&
846 846 (nUnstartedThreads == 0) && (ngroups == 0))
847 847 {
848 848 destroy();
849 849 }
850 850 }
851 851 }
852 852
853 853
854 854 /**
855 855 * Increments the count of unstarted threads in the thread group.
856 856 * Unstarted threads are not added to the thread group so that they
857 857 * can be collected if they are never started, but they must be
858 858 * counted so that daemon thread groups with unstarted threads in
859 859 * them are not destroyed.
860 860 */
861 861 void addUnstarted() {
862 862 synchronized(this) {
↓ open down ↓ |
862 lines elided |
↑ open up ↑ |
863 863 if (destroyed) {
864 864 throw new IllegalThreadStateException();
865 865 }
866 866 nUnstartedThreads++;
867 867 }
868 868 }
869 869
870 870 /**
871 871 * Notifies the group that the thread {@code t} is about to be
872 872 * started and adds the thread to this thread group.
873 + *
874 + * The thread is now a fully fledged member of the group, even though
875 + * it hasn't been started yet. It will prevent the group from being
876 + * destroyed so the unstarted Threads count is decremented.
873 877 */
874 878 void threadStarting(Thread t) {
875 - add(t);
879 + synchronized (this) {
880 + add(t);
881 + nUnstartedThreads--;
882 + }
876 883 }
877 884
878 885 /**
879 886 * Adds the specified thread to this thread group.
880 887 *
881 888 * <p> Note: This method is called from both library code
882 889 * and the Virtual Machine. It is called from VM to add
883 890 * certain system threads to the system thread group.
884 891 *
885 892 * @param t
886 893 * the Thread to be added
887 894 *
888 895 * @throws IllegalThreadStateException
889 896 * if the Thread group has been destroyed
890 897 */
891 898 void add(Thread t) {
892 899 synchronized (this) {
893 900 if (destroyed) {
894 901 throw new IllegalThreadStateException();
895 902 }
896 903 if (threads == null) {
897 904 threads = new Thread[4];
898 905 } else if (nthreads == threads.length) {
899 906 threads = Arrays.copyOf(threads, nthreads * 2);
↓ open down ↓ |
14 lines elided |
↑ open up ↑ |
900 907 }
901 908 threads[nthreads] = t;
902 909
903 910 // This is done last so it doesn't matter in case the
904 911 // thread is killed
905 912 nthreads++;
906 913 }
907 914 }
908 915
909 916 /**
910 - * Notifies the group that the thread {@code t} has completed
917 + * Notifies the group that the thread {@code t} has failed
911 918 * an attempt to start.
912 919 *
913 - * <p> If the thread has been started successfully
914 - * then the group has its unstarted Threads count decremented.
915 - * Otherwise the state of this thread group is rolled back as if the
920 + * <p> The state of this thread group is rolled back as if the
916 921 * attempt to start the thread has never occurred. The thread is again
917 922 * considered an unstarted member of the thread group, and a subsequent
918 923 * attempt to start the thread is permitted.
919 924 *
920 925 * @param t
921 926 * the Thread whose start method was invoked
922 927 *
923 928 * @param failed
924 929 * true if the thread could not be started successfully
925 930 */
926 - void threadStarted(Thread t, boolean failed) {
931 + void threadStartFailed(Thread t) {
927 932 synchronized(this) {
928 - if (failed) {
929 - remove(t);
930 - } else {
931 - if (destroyed) {
932 - return;
933 - }
934 - nUnstartedThreads--;
935 - }
933 + remove(t);
934 + nUnstartedThreads++;
936 935 }
937 936 }
938 937
939 938 /**
940 939 * Notifies the group that the thread {@code t} has terminated.
941 940 *
942 941 * <p> Destroy the group if all of the following conditions are
943 942 * true: this is a daemon thread group; there are no more alive
944 943 * or unstarted threads in the group; there are no subgroups in
945 944 * this thread group.
946 945 *
947 946 * @param t
948 947 * the Thread that has terminated
949 948 */
950 949 void threadTerminated(Thread t) {
951 950 synchronized (this) {
952 951 remove(t);
953 952
954 953 if (nthreads == 0) {
955 954 notifyAll();
956 955 }
957 956 if (daemon && (nthreads == 0) &&
958 957 (nUnstartedThreads == 0) && (ngroups == 0))
959 958 {
960 959 destroy();
961 960 }
962 961 }
963 962 }
964 963
965 964 /**
966 965 * Removes the specified Thread from this group. Invoking this method
967 966 * on a thread group that has been destroyed has no effect.
968 967 *
969 968 * @param t
970 969 * the Thread to be removed
971 970 */
972 971 private void remove(Thread t) {
973 972 synchronized (this) {
974 973 if (destroyed) {
975 974 return;
976 975 }
977 976 for (int i = 0 ; i < nthreads ; i++) {
978 977 if (threads[i] == t) {
979 978 System.arraycopy(threads, i + 1, threads, i, --nthreads - i);
980 979 // Zap dangling reference to the dead thread so that
981 980 // the garbage collector will collect it.
982 981 threads[nthreads] = null;
983 982 break;
984 983 }
985 984 }
986 985 }
987 986 }
988 987
989 988 /**
990 989 * Prints information about this thread group to the standard
991 990 * output. This method is useful only for debugging.
992 991 *
993 992 * @since JDK1.0
994 993 */
995 994 public void list() {
996 995 list(System.out, 0);
997 996 }
998 997 void list(PrintStream out, int indent) {
999 998 int ngroupsSnapshot;
1000 999 ThreadGroup[] groupsSnapshot;
1001 1000 synchronized (this) {
1002 1001 for (int j = 0 ; j < indent ; j++) {
1003 1002 out.print(" ");
1004 1003 }
1005 1004 out.println(this);
1006 1005 indent += 4;
1007 1006 for (int i = 0 ; i < nthreads ; i++) {
1008 1007 for (int j = 0 ; j < indent ; j++) {
1009 1008 out.print(" ");
1010 1009 }
1011 1010 out.println(threads[i]);
1012 1011 }
1013 1012 ngroupsSnapshot = ngroups;
1014 1013 if (groups != null) {
1015 1014 groupsSnapshot = Arrays.copyOf(groups, ngroupsSnapshot);
1016 1015 } else {
1017 1016 groupsSnapshot = null;
1018 1017 }
1019 1018 }
1020 1019 for (int i = 0 ; i < ngroupsSnapshot ; i++) {
1021 1020 groupsSnapshot[i].list(out, indent);
1022 1021 }
1023 1022 }
1024 1023
1025 1024 /**
1026 1025 * Called by the Java Virtual Machine when a thread in this
1027 1026 * thread group stops because of an uncaught exception, and the thread
1028 1027 * does not have a specific {@link Thread.UncaughtExceptionHandler}
1029 1028 * installed.
1030 1029 * <p>
1031 1030 * The <code>uncaughtException</code> method of
1032 1031 * <code>ThreadGroup</code> does the following:
1033 1032 * <ul>
1034 1033 * <li>If this thread group has a parent thread group, the
1035 1034 * <code>uncaughtException</code> method of that parent is called
1036 1035 * with the same two arguments.
1037 1036 * <li>Otherwise, this method checks to see if there is a
1038 1037 * {@linkplain Thread#getDefaultUncaughtExceptionHandler default
1039 1038 * uncaught exception handler} installed, and if so, its
1040 1039 * <code>uncaughtException</code> method is called with the same
1041 1040 * two arguments.
1042 1041 * <li>Otherwise, this method determines if the <code>Throwable</code>
1043 1042 * argument is an instance of {@link ThreadDeath}. If so, nothing
1044 1043 * special is done. Otherwise, a message containing the
1045 1044 * thread's name, as returned from the thread's {@link
1046 1045 * Thread#getName getName} method, and a stack backtrace,
1047 1046 * using the <code>Throwable</code>'s {@link
1048 1047 * Throwable#printStackTrace printStackTrace} method, is
1049 1048 * printed to the {@linkplain System#err standard error stream}.
1050 1049 * </ul>
1051 1050 * <p>
1052 1051 * Applications can override this method in subclasses of
1053 1052 * <code>ThreadGroup</code> to provide alternative handling of
1054 1053 * uncaught exceptions.
1055 1054 *
1056 1055 * @param t the thread that is about to exit.
1057 1056 * @param e the uncaught exception.
1058 1057 * @since JDK1.0
1059 1058 */
1060 1059 public void uncaughtException(Thread t, Throwable e) {
1061 1060 if (parent != null) {
1062 1061 parent.uncaughtException(t, e);
1063 1062 } else {
1064 1063 Thread.UncaughtExceptionHandler ueh =
1065 1064 Thread.getDefaultUncaughtExceptionHandler();
1066 1065 if (ueh != null) {
1067 1066 ueh.uncaughtException(t, e);
1068 1067 } else if (!(e instanceof ThreadDeath)) {
1069 1068 System.err.print("Exception in thread \""
1070 1069 + t.getName() + "\" ");
1071 1070 e.printStackTrace(System.err);
1072 1071 }
1073 1072 }
1074 1073 }
1075 1074
1076 1075 /**
1077 1076 * Used by VM to control lowmem implicit suspension.
1078 1077 *
1079 1078 * @param b boolean to allow or disallow suspension
1080 1079 * @return true on success
1081 1080 * @since JDK1.1
1082 1081 * @deprecated The definition of this call depends on {@link #suspend},
1083 1082 * which is deprecated. Further, the behavior of this call
1084 1083 * was never specified.
1085 1084 */
1086 1085 @Deprecated
1087 1086 public boolean allowThreadSuspension(boolean b) {
1088 1087 this.vmAllowSuspension = b;
1089 1088 if (!b) {
1090 1089 VM.unsuspendSomeThreads();
1091 1090 }
1092 1091 return true;
1093 1092 }
1094 1093
1095 1094 /**
1096 1095 * Returns a string representation of this Thread group.
1097 1096 *
1098 1097 * @return a string representation of this thread group.
1099 1098 * @since JDK1.0
1100 1099 */
1101 1100 public String toString() {
1102 1101 return getClass().getName() + "[name=" + getName() + ",maxpri=" + maxPriority + "]";
1103 1102 }
1104 1103 }
↓ open down ↓ |
159 lines elided |
↑ open up ↑ |
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX