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