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