1. /*
  2. * @(#)ThreadGroup.java 1.46 01/11/29
  3. *
  4. * Copyright 2002 Sun Microsystems, Inc. All rights reserved.
  5. * SUN PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
  6. */
  7. package java.lang;
  8. import java.io.PrintStream;
  9. import sun.misc.VM;
  10. /**
  11. * A thread group represents a set of threads. In addition, a thread
  12. * group can also include other thread groups. The thread groups form
  13. * a tree in which every thread group except the initial thread group
  14. * has a parent.
  15. * <p>
  16. * A thread is allowed to access information about its own thread
  17. * group, but not to access information about its thread group's
  18. * parent thread group or any other thread groups.
  19. *
  20. * @author unascribed
  21. * @version 1.46, 11/29/01
  22. * @since JDK1.0
  23. */
  24. /* The locking strategy for this code is to try to lock only one level of the
  25. * tree wherever possible, but otherwise to lock from the bottom up.
  26. * That is, from child thread groups to parents.
  27. * This has the advantage of limiting the number of locks that need to be held
  28. * and in particular avoids having to grab the lock for the root thread group,
  29. * (or a global lock) which would be a source of contention on a
  30. * multi-processor system with many thread groups.
  31. * This policy often leads to taking a snapshot of the state of a thread group
  32. * and working off of that snapshot, rather than holding the thread group locked
  33. * while we work on the children.
  34. */
  35. public
  36. class ThreadGroup {
  37. ThreadGroup parent;
  38. String name;
  39. int maxPriority;
  40. boolean destroyed;
  41. boolean daemon;
  42. boolean vmAllowSuspension;
  43. int nthreads;
  44. Thread threads[];
  45. int ngroups;
  46. ThreadGroup groups[];
  47. /**
  48. * Creates an empty Thread group that is not in any Thread group.
  49. * This method is used to create the system Thread group.
  50. */
  51. private ThreadGroup() { // called from C code
  52. this.name = "system";
  53. this.maxPriority = Thread.MAX_PRIORITY;
  54. }
  55. /**
  56. * Constructs a new thread group. The parent of this new group is
  57. * the thread group of the currently running thread.
  58. * <p>
  59. * The <code>checkAccess</code> method of the parent thread group is
  60. * called with no arguments; this may result in a security exception.
  61. *
  62. * @param name the name of the new thread group.
  63. * @exception SecurityException if the current thread cannot create a
  64. * thread in the specified thread group.
  65. * @see java.lang.ThreadGroup#checkAccess()
  66. * @since JDK1.0
  67. */
  68. public ThreadGroup(String name) {
  69. this(Thread.currentThread().getThreadGroup(), name);
  70. }
  71. /**
  72. * Creates a new thread group. The parent of this new group is the
  73. * specified thread group.
  74. * <p>
  75. * The <code>checkAccess</code> method of the parent thread group is
  76. * called with no arguments; this may result in a security exception.
  77. *
  78. * @param parent the parent thread group.
  79. * @param name the name of the new thread group.
  80. * @exception NullPointerException if the thread group argument is
  81. * <code>null</code>.
  82. * @exception SecurityException if the current thread cannot create a
  83. * thread in the specified thread group.
  84. * @see java.lang.SecurityException
  85. * @see java.lang.ThreadGroup#checkAccess()
  86. * @since JDK1.0
  87. */
  88. public ThreadGroup(ThreadGroup parent, String name) {
  89. if (parent == null) {
  90. throw new NullPointerException();
  91. }
  92. parent.checkAccess();
  93. this.name = name;
  94. this.maxPriority = parent.maxPriority;
  95. this.daemon = parent.daemon;
  96. this.vmAllowSuspension = parent.vmAllowSuspension;
  97. this.parent = parent;
  98. parent.add(this);
  99. }
  100. /**
  101. * Returns the name of this thread group.
  102. *
  103. * @return the name of this thread group.
  104. * @since JDK1.0
  105. */
  106. public final String getName() {
  107. return name;
  108. }
  109. /**
  110. * Returns the parent of this thread group.
  111. * <p>
  112. * First, if the parent is not <code>null</code>, the
  113. * <code>checkAccess</code> method of the parent thread group is
  114. * called with no arguments; this may result in a security exception.
  115. *
  116. * @return the parent of this thread group. The top-level thread group
  117. * is the only thread group whose parent is <code>null</code>.
  118. * @exception SecurityException if the current thread cannot access
  119. * the parent thread group.
  120. * @see java.lang.ThreadGroup#checkAccess()
  121. * @since JDK1.0
  122. */
  123. public final ThreadGroup getParent() {
  124. if (parent != null)
  125. parent.checkAccess();
  126. return parent;
  127. }
  128. /**
  129. * Returns the maximum priority of this thread group. Threads that are
  130. * part of this group cannot have a higher priority than the maximum
  131. * priority.
  132. *
  133. * @return the maximum priority that a thread in this thread group
  134. * can have.
  135. * @since JDK1.0
  136. */
  137. public final int getMaxPriority() {
  138. return maxPriority;
  139. }
  140. /**
  141. * Tests if this thread group is a daemon thread group. A
  142. * daemon thread group is automatically destroyed when its last
  143. * thread is stopped or its last thread group is destroyed.
  144. *
  145. * @return <code>true</code> if this thread group is a daemon thread group;
  146. * <code>false</code> otherwise.
  147. * @since JDK1.0
  148. */
  149. public final boolean isDaemon() {
  150. return daemon;
  151. }
  152. /**
  153. * Tests if this thread group has been destroyed.
  154. *
  155. * @since JDK1.1
  156. */
  157. public synchronized boolean isDestroyed() {
  158. return destroyed;
  159. }
  160. /**
  161. * Changes the daemon status of this thread group.
  162. * <p>
  163. * First, the <code>checkAccess</code> method of this thread group is
  164. * called with no arguments; this may result in a security exception.
  165. * <p>
  166. * A daemon thread group is automatically destroyed when its last
  167. * thread is stopped or its last thread group is destroyed.
  168. *
  169. * @param daemon if <code>true</code>, marks this thread group as
  170. * a daemon thread group; otherwise, marks this
  171. * thread group as normal.
  172. * @exception SecurityException if the current thread cannot modify
  173. * this thread group.
  174. * @see java.lang.SecurityException
  175. * @see java.lang.ThreadGroup#checkAccess()
  176. * @since JDK1.0
  177. */
  178. public final void setDaemon(boolean daemon) {
  179. checkAccess();
  180. this.daemon = daemon;
  181. }
  182. /**
  183. * Sets the maximum priority of the group.
  184. * <p>
  185. * First, the <code>checkAccess</code> method of this thread group is
  186. * called with no arguments; this may result in a security exception.
  187. * <p>
  188. * Threads in the thread group that already have a higher priority
  189. * are not affected.
  190. *
  191. * @param pri the new priority of the thread group.
  192. * @exception SecurityException if the current thread cannot modify
  193. * this thread group.
  194. * @see java.lang.SecurityException
  195. * @see java.lang.ThreadGroup#checkAccess()
  196. * @since JDK1.0
  197. */
  198. public final void setMaxPriority(int pri) {
  199. int ngroupsSnapshot;
  200. ThreadGroup[] groupsSnapshot;
  201. synchronized (this) {
  202. checkAccess();
  203. if (pri < Thread.MIN_PRIORITY) {
  204. maxPriority = Thread.MIN_PRIORITY;
  205. } else if (pri < maxPriority) {
  206. maxPriority = pri;
  207. }
  208. ngroupsSnapshot = ngroups;
  209. if (groups != null) {
  210. groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
  211. System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
  212. } else {
  213. groupsSnapshot = null;
  214. }
  215. }
  216. for (int i = 0 ; i < ngroupsSnapshot ; i++) {
  217. groupsSnapshot[i].setMaxPriority(pri);
  218. }
  219. }
  220. /**
  221. * Tests if this thread group is either the thread group
  222. * argument or one of its ancestor thread groups.
  223. *
  224. * @param g a thread group.
  225. * @return <code>true</code> if this thread group is the thread group
  226. * argument or one of its ancestor thread groups;
  227. * <code>false</code> otherwise.
  228. * @since JDK1.0
  229. */
  230. public final boolean parentOf(ThreadGroup g) {
  231. for (; g != null ; g = g.parent) {
  232. if (g == this) {
  233. return true;
  234. }
  235. }
  236. return false;
  237. }
  238. /**
  239. * Determines if the currently running thread has permission to
  240. * modify this thread group.
  241. * <p>
  242. * If there is a security manager, its <code>checkAccess</code> method
  243. * is called with this thread group as its argument. This may result
  244. * in throwing a <code>SecurityException</code>.
  245. *
  246. * @exception SecurityException if the current thread is not allowed to
  247. * access this thread group.
  248. * @see java.lang.SecurityManager#checkAccess(java.lang.ThreadGroup)
  249. * @since JDK1.0
  250. */
  251. public final void checkAccess() {
  252. SecurityManager security = System.getSecurityManager();
  253. if (security != null) {
  254. security.checkAccess(this);
  255. }
  256. }
  257. /**
  258. * Returns an estimate of the number of active threads in this
  259. * thread group.
  260. *
  261. * @return the number of active threads in this thread group and in any
  262. * other thread group that has this thread group as an ancestor.
  263. * @since JDK1.0
  264. */
  265. public int activeCount() {
  266. int result;
  267. // Snapshot sub-group data so we don't hold this lock
  268. // while our children are computing.
  269. int ngroupsSnapshot;
  270. ThreadGroup[] groupsSnapshot;
  271. synchronized (this) {
  272. if (destroyed) {
  273. return 0;
  274. }
  275. result = nthreads;
  276. ngroupsSnapshot = ngroups;
  277. if (groups != null) {
  278. groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
  279. System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
  280. } else {
  281. groupsSnapshot = null;
  282. }
  283. }
  284. for (int i = 0 ; i < ngroupsSnapshot ; i++) {
  285. result += groupsSnapshot[i].activeCount();
  286. }
  287. return result;
  288. }
  289. /**
  290. * Copies into the specified array every active thread in this
  291. * thread group and its subgroups.
  292. * <p>
  293. * First, the <code>checkAccess</code> method of this thread group is
  294. * called with no arguments; this may result in a security exception.
  295. * <p>
  296. * An application should use the <code>activeCount</code> method to
  297. * get an estimate of how big the array should be. If the array is
  298. * too short to hold all the threads, the extra threads are silently
  299. * ignored.
  300. *
  301. * @param list an array into which to place the list of threads.
  302. * @return the number of threads put into the array.
  303. * @exception SecurityException if the current thread does not
  304. * have permission to enumerate this thread group.
  305. * @see java.lang.ThreadGroup#activeCount()
  306. * @see java.lang.ThreadGroup#checkAccess()
  307. * @since JDK1.0
  308. */
  309. public int enumerate(Thread list[]) {
  310. checkAccess();
  311. return enumerate(list, 0, true);
  312. }
  313. /**
  314. * Copies into the specified array every active thread in this
  315. * thread group. If the <code>recurse</code> flag is
  316. * <code>true</code>, references to every active thread in this
  317. * thread's subgroups are also included. If the array is too short to
  318. * hold all the threads, the extra threads are silently ignored.
  319. * <p>
  320. * First, the <code>checkAccess</code> method of this thread group is
  321. * called with no arguments; this may result in a security exception.
  322. * <p>
  323. * An application should use the <code>activeCount</code> method to
  324. * get an estimate of how big the array should be.
  325. *
  326. * @param list an array into which to place the list of threads.
  327. * @param recurse a flag indicating whether also to include threads
  328. * in thread groups that are subgroups of this
  329. * thread group.
  330. * @return the number of threads placed into the array.
  331. * @exception SecurityException if the current thread does not
  332. * have permission to enumerate this thread group.
  333. * @see java.lang.ThreadGroup#activeCount()
  334. * @see java.lang.ThreadGroup#checkAccess()
  335. * @since JDK1.0
  336. */
  337. public int enumerate(Thread list[], boolean recurse) {
  338. checkAccess();
  339. return enumerate(list, 0, recurse);
  340. }
  341. private int enumerate(Thread list[], int n, boolean recurse) {
  342. int ngroupsSnapshot = 0;
  343. ThreadGroup[] groupsSnapshot = null;
  344. synchronized (this) {
  345. if (destroyed) {
  346. return 0;
  347. }
  348. int nt = nthreads;
  349. if (nt > list.length - n) {
  350. nt = list.length - n;
  351. }
  352. for (int i = 0; i < nt; i++) {
  353. if (threads[i].isAlive()) {
  354. list[n++] = threads[i];
  355. }
  356. }
  357. if (recurse) {
  358. ngroupsSnapshot = ngroups;
  359. if (groups != null) {
  360. groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
  361. System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
  362. } else {
  363. groupsSnapshot = null;
  364. }
  365. }
  366. }
  367. if (recurse) {
  368. for (int i = 0 ; i < ngroupsSnapshot ; i++) {
  369. n = groupsSnapshot[i].enumerate(list, n, true);
  370. }
  371. }
  372. return n;
  373. }
  374. /**
  375. * Returns an estimate of the number of active groups in this
  376. * thread group.
  377. *
  378. * @return the number of active thread groups with this thread group as
  379. * an ancestor.
  380. * @since JDK1.0
  381. */
  382. public int activeGroupCount() {
  383. int ngroupsSnapshot;
  384. ThreadGroup[] groupsSnapshot;
  385. synchronized (this) {
  386. if (destroyed) {
  387. return 0;
  388. }
  389. ngroupsSnapshot = ngroups;
  390. if (groups != null) {
  391. groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
  392. System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
  393. } else {
  394. groupsSnapshot = null;
  395. }
  396. }
  397. int n = ngroupsSnapshot;
  398. for (int i = 0 ; i < ngroupsSnapshot ; i++) {
  399. n += groupsSnapshot[i].activeGroupCount();
  400. }
  401. return n;
  402. }
  403. /**
  404. * Copies into the specified array references to every active
  405. * subgroup in this thread group.
  406. * <p>
  407. * First, the <code>checkAccess</code> method of this thread group is
  408. * called with no arguments; this may result in a security exception.
  409. * <p>
  410. * An application should use the <code>activeGroupCount</code>
  411. * method to get an estimate of how big the array should be. If the
  412. * array is too short to hold all the thread groups, the extra thread
  413. * groups are silently ignored.
  414. *
  415. * @param list an array into which to place the list of thread groups.
  416. * @return the number of thread groups put into the array.
  417. * @exception SecurityException if the current thread does not
  418. * have permission to enumerate this thread group.
  419. * @see java.lang.ThreadGroup#activeGroupCount()
  420. * @see java.lang.ThreadGroup#checkAccess()
  421. * @since JDK1.0
  422. */
  423. public int enumerate(ThreadGroup list[]) {
  424. checkAccess();
  425. return enumerate(list, 0, true);
  426. }
  427. /**
  428. * Copies into the specified array references to every active
  429. * subgroup in this thread group. If the <code>recurse</code> flag is
  430. * <code>true</code>, references to all active subgroups of the
  431. * subgroups and so forth are also included.
  432. * <p>
  433. * First, the <code>checkAccess</code> method of this thread group is
  434. * called with no arguments; this may result in a security exception.
  435. * <p>
  436. * An application should use the <code>activeGroupCount</code>
  437. * method to get an estimate of how big the array should be.
  438. *
  439. * @param list an array into which to place the list of threads.
  440. * @param recurse a flag indicating whether to recursively enumerate
  441. * all included thread groups.
  442. * @return the number of thread groups put into the array.
  443. * @exception SecurityException if the current thread does not
  444. * have permission to enumerate this thread group.
  445. * @see java.lang.ThreadGroup#activeGroupCount()
  446. * @see java.lang.ThreadGroup#checkAccess()
  447. * @since JDK1.0
  448. */
  449. public int enumerate(ThreadGroup list[], boolean recurse) {
  450. checkAccess();
  451. return enumerate(list, 0, recurse);
  452. }
  453. private int enumerate(ThreadGroup list[], int n, boolean recurse) {
  454. int ngroupsSnapshot = 0;
  455. ThreadGroup[] groupsSnapshot = null;
  456. synchronized (this) {
  457. if (destroyed) {
  458. return 0;
  459. }
  460. int ng = ngroups;
  461. if (ng > list.length - n) {
  462. ng = list.length - n;
  463. }
  464. if (ng > 0) {
  465. System.arraycopy(groups, 0, list, n, ng);
  466. n += ng;
  467. }
  468. if (recurse) {
  469. ngroupsSnapshot = ngroups;
  470. if (groups != null) {
  471. groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
  472. System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
  473. } else {
  474. groupsSnapshot = null;
  475. }
  476. }
  477. }
  478. if (recurse) {
  479. for (int i = 0 ; i < ngroupsSnapshot ; i++) {
  480. n = groupsSnapshot[i].enumerate(list, n, true);
  481. }
  482. }
  483. return n;
  484. }
  485. /**
  486. * Stops all threads in this thread group.
  487. * <p>
  488. * First, the <code>checkAccess</code> method of this thread group is
  489. * called with no arguments; this may result in a security exception.
  490. * <p>
  491. * This method then calls the <code>stop</code> method on all the
  492. * threads in this thread group and in all of its subgroups.
  493. *
  494. * @exception SecurityException if the current thread is not allowed
  495. * to access this thread group or any of the threads in
  496. * the thread group.
  497. * @see java.lang.SecurityException
  498. * @see java.lang.Thread#stop()
  499. * @see java.lang.ThreadGroup#checkAccess()
  500. * @since JDK1.0
  501. * @deprecated This method is inherently unsafe. See
  502. * {@link Thread#stop} for details.
  503. */
  504. public final void stop() {
  505. if (stopOrSuspend(false))
  506. Thread.currentThread().stop();
  507. }
  508. /**
  509. * Interrupts all threads in this thread group.
  510. * <p>
  511. * First, the <code>checkAccess</code> method of this thread group is
  512. * called with no arguments; this may result in a security exception.
  513. * <p>
  514. * This method then calls the <code>interrupt</code> method on all the
  515. * threads in this thread group and in all of its subgroups.
  516. *
  517. * @exception SecurityException if the current thread is not allowed
  518. * to access this thread group or any of the threads in
  519. * the thread group.
  520. * @see java.lang.Thread#interrupt()
  521. * @see java.lang.SecurityException
  522. * @see java.lang.ThreadGroup#checkAccess()
  523. * @since JDK1.2
  524. */
  525. public final void interrupt() {
  526. int ngroupsSnapshot;
  527. ThreadGroup[] groupsSnapshot;
  528. synchronized (this) {
  529. checkAccess();
  530. for (int i = 0 ; i < nthreads ; i++) {
  531. threads[i].interrupt();
  532. }
  533. ngroupsSnapshot = ngroups;
  534. if (groups != null) {
  535. groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
  536. System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
  537. } else {
  538. groupsSnapshot = null;
  539. }
  540. }
  541. for (int i = 0 ; i < ngroupsSnapshot ; i++) {
  542. groupsSnapshot[i].interrupt();
  543. }
  544. }
  545. /**
  546. * Suspends all threads in this thread group.
  547. * <p>
  548. * First, the <code>checkAccess</code> method of this thread group is
  549. * called with no arguments; this may result in a security exception.
  550. * <p>
  551. * This method then calls the <code>suspend</code> method on all the
  552. * threads in this thread group and in all of its subgroups.
  553. *
  554. * @exception SecurityException if the current thread is not allowed
  555. * to access this thread group or any of the threads in
  556. * the thread group.
  557. * @see java.lang.Thread#suspend()
  558. * @see java.lang.SecurityException
  559. * @see java.lang.ThreadGroup#checkAccess()
  560. * @since JDK1.0
  561. * @deprecated This method is inherently deadlock-prone. See
  562. * {@link Thread#suspend} for details.
  563. */
  564. public final void suspend() {
  565. if (stopOrSuspend(true))
  566. Thread.currentThread().suspend();
  567. }
  568. /**
  569. * Helper method: recursively stops or suspends (as directed by the
  570. * boolean argument) all of the threads in this thread group and its
  571. * subgroups, except the current thread. This method returns true
  572. * if (and only if) the current thread is found to be in this thread
  573. * group or one of its subgroups.
  574. */
  575. private boolean stopOrSuspend(boolean suspend) {
  576. boolean suicide = false;
  577. Thread us = Thread.currentThread();
  578. int ngroupsSnapshot;
  579. ThreadGroup[] groupsSnapshot = null;
  580. synchronized (this) {
  581. checkAccess();
  582. for (int i = 0 ; i < nthreads ; i++) {
  583. if (threads[i]==us)
  584. suicide = true;
  585. else if (suspend)
  586. threads[i].suspend();
  587. else
  588. threads[i].stop();
  589. }
  590. ngroupsSnapshot = ngroups;
  591. if (groups != null) {
  592. groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
  593. System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
  594. }
  595. }
  596. for (int i = 0 ; i < ngroupsSnapshot ; i++)
  597. suicide = groupsSnapshot[i].stopOrSuspend(suspend) || suicide;
  598. return suicide;
  599. }
  600. /**
  601. * Resumes all threads in this thread group.
  602. * <p>
  603. * First, the <code>checkAccess</code> method of this thread group is
  604. * called with no arguments; this may result in a security exception.
  605. * <p>
  606. * This method then calls the <code>resume</code> method on all the
  607. * threads in this thread group and in all of its sub groups.
  608. *
  609. * @exception SecurityException if the current thread is not allowed to
  610. * access this thread group or any of the threads in the
  611. * thread group.
  612. * @see java.lang.SecurityException
  613. * @see java.lang.Thread#resume()
  614. * @see java.lang.ThreadGroup#checkAccess()
  615. * @since JDK1.0
  616. * @deprecated This method is used solely in conjunction with
  617. * <tt>Thread.suspend</tt> and <tt>ThreadGroup.suspend</tt>,
  618. * both of which have been deprecated, as they are inherently
  619. * deadlock-prone. See {@link Thread#suspend} for details.
  620. */
  621. public final void resume() {
  622. int ngroupsSnapshot;
  623. ThreadGroup[] groupsSnapshot;
  624. synchronized (this) {
  625. checkAccess();
  626. for (int i = 0 ; i < nthreads ; i++) {
  627. threads[i].resume();
  628. }
  629. ngroupsSnapshot = ngroups;
  630. if (groups != null) {
  631. groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
  632. System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
  633. } else {
  634. groupsSnapshot = null;
  635. }
  636. }
  637. for (int i = 0 ; i < ngroupsSnapshot ; i++) {
  638. groupsSnapshot[i].resume();
  639. }
  640. }
  641. /**
  642. * Destroys this thread group and all of its subgroups. This thread
  643. * group must be empty, indicating that all threads that had been in
  644. * this thread group have since stopped.
  645. * <p>
  646. * First, the <code>checkAccess</code> method of this thread group is
  647. * called with no arguments; this may result in a security exception.
  648. *
  649. * @exception IllegalThreadStateException if the thread group is not
  650. * empty or if the thread group has already been destroyed.
  651. * @exception SecurityException if the current thread cannot modify this
  652. * thread group.
  653. * @see java.lang.ThreadGroup#checkAccess()
  654. * @since JDK1.0
  655. */
  656. public final void destroy() {
  657. int ngroupsSnapshot;
  658. ThreadGroup[] groupsSnapshot;
  659. synchronized (this) {
  660. checkAccess();
  661. if (destroyed || (nthreads > 0)) {
  662. throw new IllegalThreadStateException();
  663. }
  664. ngroupsSnapshot = ngroups;
  665. if (groups != null) {
  666. groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
  667. System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
  668. } else {
  669. groupsSnapshot = null;
  670. }
  671. if (parent != null) {
  672. destroyed = true;
  673. ngroups = 0;
  674. groups = null;
  675. nthreads = 0;
  676. threads = null;
  677. }
  678. }
  679. for (int i = 0 ; i < ngroupsSnapshot ; i += 1) {
  680. groupsSnapshot[i].destroy();
  681. }
  682. if (parent != null) {
  683. parent.remove(this);
  684. }
  685. }
  686. /**
  687. * Adds the specified Thread group to this group.
  688. * @param g the specified Thread group to be added
  689. * @exception IllegalThreadStateException If the Thread group has been destroyed.
  690. */
  691. private final void add(ThreadGroup g){
  692. synchronized (this) {
  693. if (destroyed) {
  694. throw new IllegalThreadStateException();
  695. }
  696. if (groups == null) {
  697. groups = new ThreadGroup[4];
  698. } else if (ngroups == groups.length) {
  699. ThreadGroup newgroups[] = new ThreadGroup[ngroups * 2];
  700. System.arraycopy(groups, 0, newgroups, 0, ngroups);
  701. groups = newgroups;
  702. }
  703. groups[ngroups] = g;
  704. // This is done last so it doesn't matter in case the
  705. // thread is killed
  706. ngroups++;
  707. }
  708. }
  709. /**
  710. * Removes the specified Thread group from this group.
  711. * @param g the Thread group to be removed
  712. * @return if this Thread has already been destroyed.
  713. */
  714. private void remove(ThreadGroup g) {
  715. synchronized (this) {
  716. if (destroyed) {
  717. return;
  718. }
  719. for (int i = 0 ; i < ngroups ; i++) {
  720. if (groups[i] == g) {
  721. ngroups -= 1;
  722. System.arraycopy(groups, i + 1, groups, i, ngroups - i);
  723. // Zap dangling reference to the dead group so that
  724. // the garbage collector will collect it.
  725. groups[ngroups] = null;
  726. break;
  727. }
  728. }
  729. if (nthreads == 0) {
  730. notifyAll();
  731. }
  732. if (daemon && (nthreads == 0) && (ngroups == 0)) {
  733. destroy();
  734. }
  735. }
  736. }
  737. /**
  738. * Adds the specified Thread to this group.
  739. * @param t the Thread to be added
  740. * @exception IllegalThreadStateException If the Thread group has been destroyed.
  741. */
  742. void add(Thread t) {
  743. synchronized (this) {
  744. if (destroyed) {
  745. throw new IllegalThreadStateException();
  746. }
  747. if (threads == null) {
  748. threads = new Thread[4];
  749. } else if (nthreads == threads.length) {
  750. Thread newthreads[] = new Thread[nthreads * 2];
  751. System.arraycopy(threads, 0, newthreads, 0, nthreads);
  752. threads = newthreads;
  753. }
  754. threads[nthreads] = t;
  755. // This is done last so it doesn't matter in case the
  756. // thread is killed
  757. nthreads++;
  758. }
  759. }
  760. /**
  761. * Removes the specified Thread from this group.
  762. * @param t the Thread to be removed
  763. * @return if the Thread has already been destroyed.
  764. */
  765. void remove(Thread t) {
  766. synchronized (this) {
  767. if (destroyed) {
  768. return;
  769. }
  770. for (int i = 0 ; i < nthreads ; i++) {
  771. if (threads[i] == t) {
  772. System.arraycopy(threads, i + 1, threads, i, --nthreads - i);
  773. // Zap dangling reference to the dead thread so that
  774. // the garbage collector will collect it.
  775. threads[nthreads] = null;
  776. break;
  777. }
  778. }
  779. if (nthreads == 0) {
  780. notifyAll();
  781. }
  782. if (daemon && (nthreads == 0) && (ngroups == 0)) {
  783. destroy();
  784. }
  785. }
  786. }
  787. /**
  788. * Prints information about this thread group to the standard
  789. * output. This method is useful only for debugging.
  790. *
  791. * @since JDK1.0
  792. */
  793. public void list() {
  794. list(System.out, 0);
  795. }
  796. void list(PrintStream out, int indent) {
  797. int ngroupsSnapshot;
  798. ThreadGroup[] groupsSnapshot;
  799. synchronized (this) {
  800. for (int j = 0 ; j < indent ; j++) {
  801. out.print(" ");
  802. }
  803. out.println(this);
  804. indent += 4;
  805. for (int i = 0 ; i < nthreads ; i++) {
  806. for (int j = 0 ; j < indent ; j++) {
  807. out.print(" ");
  808. }
  809. out.println(threads[i]);
  810. }
  811. ngroupsSnapshot = ngroups;
  812. if (groups != null) {
  813. groupsSnapshot = new ThreadGroup[ngroupsSnapshot];
  814. System.arraycopy(groups, 0, groupsSnapshot, 0, ngroupsSnapshot);
  815. } else {
  816. groupsSnapshot = null;
  817. }
  818. }
  819. for (int i = 0 ; i < ngroupsSnapshot ; i++) {
  820. groupsSnapshot[i].list(out, indent);
  821. }
  822. }
  823. /**
  824. * Called by the Java Virtual Machine when a thread in this
  825. * thread group stops because of an uncaught exception.
  826. * <p>
  827. * The <code>uncaughtException</code> method of
  828. * <code>ThreadGroup</code> does the following:
  829. * <ul>
  830. * <li>If this thread group has a parent thread group, the
  831. * <code>uncaughtException</code> method of that parent is called
  832. * with the same two arguments.
  833. * <li>Otherwise, this method determines if the <code>Throwable</code>
  834. * argument is an instance of <code>ThreadDeath</code>. If so, nothing
  835. * special is done. Otherwise, the <code>Throwable</code>'s
  836. * <code>printStackTrace</code> method is called to print a stack
  837. * backtrace to the standard error stream.
  838. * </ul>
  839. * <p>
  840. * Applications can override this method in subclasses of
  841. * <code>ThreadGroup</code> to provide alternative handling of
  842. * uncaught exceptions.
  843. *
  844. * @param t the thread that is about to exit.
  845. * @param e the uncaught exception.
  846. * @see java.lang.System#err
  847. * @see java.lang.ThreadDeath
  848. * @see java.lang.Throwable#printStackTrace(java.io.PrintStream)
  849. * @since JDK1.0
  850. */
  851. public void uncaughtException(Thread t, Throwable e) {
  852. if (parent != null) {
  853. parent.uncaughtException(t, e);
  854. } else if (!(e instanceof ThreadDeath)) {
  855. e.printStackTrace(System.err);
  856. }
  857. }
  858. /**
  859. * Used by VM to control lowmem implicit suspension.
  860. *
  861. * @since JDK1.1
  862. * @deprecated The definition of this call depends on {@link #suspend},
  863. * which is deprecated. Further, the behavior of this call
  864. * was never specified.
  865. */
  866. public boolean allowThreadSuspension(boolean b) {
  867. this.vmAllowSuspension = b;
  868. if (!b) {
  869. VM.unsuspendSomeThreads();
  870. }
  871. return true;
  872. }
  873. /**
  874. * Returns a string representation of this Thread group.
  875. *
  876. * @return a string representation of this thread group.
  877. * @since JDK1.0
  878. */
  879. public String toString() {
  880. return getClass().getName() + "[name=" + getName() + ",maxpri=" + maxPriority + "]";
  881. }
  882. }