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