diff options
Diffstat (limited to 'java/lang')
-rw-r--r-- | java/lang/Iterable.java | 3 | ||||
-rw-r--r-- | java/lang/StrictMath.java | 652 | ||||
-rw-r--r-- | java/lang/management/ManagementFactory.java | 104 | ||||
-rw-r--r-- | java/lang/management/MemoryMXBean.java | 28 | ||||
-rw-r--r-- | java/lang/management/MemoryNotificationInfo.java | 215 | ||||
-rw-r--r-- | java/lang/management/MemoryPoolMXBean.java | 8 | ||||
-rw-r--r-- | java/lang/management/MemoryUsage.java | 45 | ||||
-rw-r--r-- | java/lang/management/ThreadInfo.java | 271 |
8 files changed, 1282 insertions, 44 deletions
diff --git a/java/lang/Iterable.java b/java/lang/Iterable.java index 8223bcf8c..35c426484 100644 --- a/java/lang/Iterable.java +++ b/java/lang/Iterable.java @@ -38,7 +38,8 @@ exception statement from your version. */ package java.lang; -import java.util.Iterator; +// We only need Iterator, but we import * to support lib/mkcollections.pl +import java.util.*; /** * This interface is used to indicate that a given class can be diff --git a/java/lang/StrictMath.java b/java/lang/StrictMath.java index 548a6f1c1..ec74ca413 100644 --- a/java/lang/StrictMath.java +++ b/java/lang/StrictMath.java @@ -1,5 +1,5 @@ /* java.lang.StrictMath -- common mathematical functions, strict Java - Copyright (C) 1998, 2001, 2002, 2003 Free Software Foundation, Inc. + Copyright (C) 1998, 2001, 2002, 2003, 2006 Free Software Foundation, Inc. This file is part of GNU Classpath. @@ -633,6 +633,381 @@ public final strictfp class StrictMath } /** + * Returns the hyperbolic sine of <code>x</code> which is defined as + * (exp(x) - exp(-x)) / 2. + * + * Special cases: + * <ul> + * <li>If the argument is NaN, the result is NaN</li> + * <li>If the argument is positive infinity, the result is positive + * infinity.</li> + * <li>If the argument is negative infinity, the result is negative + * infinity.</li> + * <li>If the argument is zero, the result is zero.</li> + * </ul> + * + * @param x the argument to <em>sinh</em> + * @return the hyperbolic sine of <code>x</code> + * + * @since 1.5 + */ + public static double sinh(double x) + { + // Method : + // mathematically sinh(x) if defined to be (exp(x)-exp(-x))/2 + // 1. Replace x by |x| (sinh(-x) = -sinh(x)). + // 2. + // E + E/(E+1) + // 0 <= x <= 22 : sinh(x) := --------------, E=expm1(x) + // 2 + // + // 22 <= x <= lnovft : sinh(x) := exp(x)/2 + // lnovft <= x <= ln2ovft: sinh(x) := exp(x/2)/2 * exp(x/2) + // ln2ovft < x : sinh(x) := +inf (overflow) + + double t, w, h; + + long bits; + long h_bits; + long l_bits; + + // handle special cases + if (x != x) + return x; + if (x == Double.POSITIVE_INFINITY) + return Double.POSITIVE_INFINITY; + if (x == Double.NEGATIVE_INFINITY) + return Double.NEGATIVE_INFINITY; + + if (x < 0) + h = - 0.5; + else + h = 0.5; + + bits = Double.doubleToLongBits(x); + h_bits = getHighDWord(bits) & 0x7fffffffL; // ignore sign + l_bits = getLowDWord(bits); + + // |x| in [0, 22], return sign(x) * 0.5 * (E+E/(E+1)) + if (h_bits < 0x40360000L) // |x| < 22 + { + if (h_bits < 0x3e300000L) // |x| < 2^-28 + return x; // for tiny arguments return x + + t = expm1(abs(x)); + + if (h_bits < 0x3ff00000L) + return h * (2.0 * t - t * t / (t + 1.0)); + + return h * (t + t / (t + 1.0)); + } + + // |x| in [22, log(Double.MAX_VALUE)], return 0.5 * exp(|x|) + if (h_bits < 0x40862e42L) + return h * exp(abs(x)); + + // |x| in [log(Double.MAX_VALUE), overflowthreshold] + if ((h_bits < 0x408633ceL) + || ((h_bits == 0x408633ceL) && (l_bits <= 0x8fb9f87dL))) + { + w = exp(0.5 * abs(x)); + t = h * w; + + return t * w; + } + + // |x| > overflowthershold + return h * Double.POSITIVE_INFINITY; + } + + /** + * Returns the hyperbolic cosine of <code>x</code>, which is defined as + * (exp(x) + exp(-x)) / 2. + * + * Special cases: + * <ul> + * <li>If the argument is NaN, the result is NaN</li> + * <li>If the argument is positive infinity, the result is positive + * infinity.</li> + * <li>If the argument is negative infinity, the result is positive + * infinity.</li> + * <li>If the argument is zero, the result is one.</li> + * </ul> + * + * @param x the argument to <em>cosh</em> + * @return the hyperbolic cosine of <code>x</code> + * + * @since 1.5 + */ + public static double cosh(double x) + { + // Method : + // mathematically cosh(x) if defined to be (exp(x)+exp(-x))/2 + // 1. Replace x by |x| (cosh(x) = cosh(-x)). + // 2. + // [ exp(x) - 1 ]^2 + // 0 <= x <= ln2/2 : cosh(x) := 1 + ------------------- + // 2*exp(x) + // + // exp(x) + 1/exp(x) + // ln2/2 <= x <= 22 : cosh(x) := ------------------ + // 2 + // 22 <= x <= lnovft : cosh(x) := exp(x)/2 + // lnovft <= x <= ln2ovft: cosh(x) := exp(x/2)/2 * exp(x/2) + // ln2ovft < x : cosh(x) := +inf (overflow) + + double t, w; + long bits; + long hx; + long lx; + + // handle special cases + if (x != x) + return x; + if (x == Double.POSITIVE_INFINITY) + return Double.POSITIVE_INFINITY; + if (x == Double.NEGATIVE_INFINITY) + return Double.POSITIVE_INFINITY; + + bits = Double.doubleToLongBits(x); + hx = getHighDWord(bits) & 0x7fffffffL; // ignore sign + lx = getLowDWord(bits); + + // |x| in [0, 0.5 * ln(2)], return 1 + expm1(|x|)^2 / (2 * exp(|x|)) + if (hx < 0x3fd62e43L) + { + t = expm1(abs(x)); + w = 1.0 + t; + + // for tiny arguments return 1. + if (hx < 0x3c800000L) + return w; + + return 1.0 + (t * t) / (w + w); + } + + // |x| in [0.5 * ln(2), 22], return exp(|x|)/2 + 1 / (2 * exp(|x|)) + if (hx < 0x40360000L) + { + t = exp(abs(x)); + + return 0.5 * t + 0.5 / t; + } + + // |x| in [22, log(Double.MAX_VALUE)], return 0.5 * exp(|x|) + if (hx < 0x40862e42L) + return 0.5 * exp(abs(x)); + + // |x| in [log(Double.MAX_VALUE), overflowthreshold], + // return exp(x/2)/2 * exp(x/2) + if ((hx < 0x408633ceL) + || ((hx == 0x408633ceL) && (lx <= 0x8fb9f87dL))) + { + w = exp(0.5 * abs(x)); + t = 0.5 * w; + + return t * w; + } + + // |x| > overflowthreshold + return Double.POSITIVE_INFINITY; + } + + /** + * Returns the hyperbolic tangent of <code>x</code>, which is defined as + * (exp(x) - exp(-x)) / (exp(x) + exp(-x)), i.e. sinh(x) / cosh(x). + * + Special cases: + * <ul> + * <li>If the argument is NaN, the result is NaN</li> + * <li>If the argument is positive infinity, the result is 1.</li> + * <li>If the argument is negative infinity, the result is -1.</li> + * <li>If the argument is zero, the result is zero.</li> + * </ul> + * + * @param x the argument to <em>tanh</em> + * @return the hyperbolic tagent of <code>x</code> + * + * @since 1.5 + */ + public static double tanh(double x) + { + // Method : + // 0. tanh(x) is defined to be (exp(x) - exp(-x)) / (exp(x) + exp(-x)) + // 1. reduce x to non-negative by tanh(-x) = -tanh(x). + // 2. 0 <= x <= 2^-55 : tanh(x) := x * (1.0 + x) + // -t + // 2^-55 < x <= 1 : tanh(x) := -----; t = expm1(-2x) + // t + 2 + // 2 + // 1 <= x <= 22.0 : tanh(x) := 1 - ----- ; t=expm1(2x) + // t + 2 + // 22.0 < x <= INF : tanh(x) := 1. + + double t, z; + + long bits; + long h_bits; + + // handle special cases + if (x != x) + return x; + if (x == Double.POSITIVE_INFINITY) + return 1.0; + if (x == Double.NEGATIVE_INFINITY) + return -1.0; + + bits = Double.doubleToLongBits(x); + h_bits = getHighDWord(bits) & 0x7fffffffL; // ingnore sign + + if (h_bits < 0x40360000L) // |x| < 22 + { + if (h_bits < 0x3c800000L) // |x| < 2^-55 + return x * (1.0 + x); + + if (h_bits >= 0x3ff00000L) // |x| >= 1 + { + t = expm1(2.0 * abs(x)); + z = 1.0 - 2.0 / (t + 2.0); + } + else // |x| < 1 + { + t = expm1(-2.0 * abs(x)); + z = -t / (t + 2.0); + } + } + else // |x| >= 22 + z = 1.0; + + return (x >= 0) ? z : -z; + } + + /** + * Returns the lower two words of a long. This is intended to be + * used like this: + * <code>getLowDWord(Double.doubleToLongBits(x))</code>. + */ + private static long getLowDWord(long x) + { + return x & 0x00000000ffffffffL; + } + + /** + * Returns the higher two words of a long. This is intended to be + * used like this: + * <code>getHighDWord(Double.doubleToLongBits(x))</code>. + */ + private static long getHighDWord(long x) + { + return (x & 0xffffffff00000000L) >> 32; + } + + /** + * Returns a double with the IEEE754 bit pattern given in the lower + * and higher two words <code>lowDWord</code> and <code>highDWord</code>. + */ + private static double buildDouble(long lowDWord, long highDWord) + { + return Double.longBitsToDouble(((highDWord & 0xffffffffL) << 32) + | (lowDWord & 0xffffffffL)); + } + + /** + * Returns the cube root of <code>x</code>. The sign of the cube root + * is equal to the sign of <code>x</code>. + * + * Special cases: + * <ul> + * <li>If the argument is NaN, the result is NaN</li> + * <li>If the argument is positive infinity, the result is positive + * infinity.</li> + * <li>If the argument is negative infinity, the result is negative + * infinity.</li> + * <li>If the argument is zero, the result is zero with the same + * sign as the argument.</li> + * </ul> + * + * @param x the number to take the cube root of + * @return the cube root of <code>x</code> + * @see #sqrt(double) + * + * @since 1.5 + */ + public static double cbrt(double x) + { + boolean negative = (x < 0); + double r; + double s; + double t; + double w; + + long bits; + long l; + long h; + + // handle the special cases + if (x != x) + return x; + if (x == Double.POSITIVE_INFINITY) + return Double.POSITIVE_INFINITY; + if (x == Double.NEGATIVE_INFINITY) + return Double.NEGATIVE_INFINITY; + if (x == 0) + return x; + + x = abs(x); + bits = Double.doubleToLongBits(x); + + if (bits < 0x0010000000000000L) // subnormal number + { + t = TWO_54; + t *= x; + + // __HI(t)=__HI(t)/3+B2; + bits = Double.doubleToLongBits(t); + h = getHighDWord(bits); + l = getLowDWord(bits); + + h = h / 3 + CBRT_B2; + + t = buildDouble(l, h); + } + else + { + // __HI(t)=__HI(x)/3+B1; + h = getHighDWord(bits); + l = 0; + + h = h / 3 + CBRT_B1; + t = buildDouble(l, h); + } + + // new cbrt to 23 bits + r = t * t / x; + s = CBRT_C + r * t; + t *= CBRT_G + CBRT_F / (s + CBRT_E + CBRT_D / s); + + // chopped to 20 bits and make it larger than cbrt(x) + bits = Double.doubleToLongBits(t); + h = getHighDWord(bits); + + // __LO(t)=0; + // __HI(t)+=0x00000001; + l = 0; + h += 1; + t = buildDouble(l, h); + + // one step newton iteration to 53 bits with error less than 0.667 ulps + s = t * t; // t * t is exact + r = x / s; + w = t + t; + r = (r - t) / (w + r); // r - t is exact + t = t + t * r; + + return negative ? -t : t; + } + + /** * Take <em>e</em><sup>a</sup>. The opposite of <code>log()</code>. If the * argument is NaN, the result is NaN; if the argument is positive infinity, * the result is positive infinity; and if the argument is negative @@ -694,6 +1069,254 @@ public final strictfp class StrictMath } /** + * Returns <em>e</em><sup>x</sup> - 1. + * Special cases: + * <ul> + * <li>If the argument is NaN, the result is NaN.</li> + * <li>If the argument is positive infinity, the result is positive + * infinity</li> + * <li>If the argument is negative infinity, the result is -1.</li> + * <li>If the argument is zero, the result is zero.</li> + * </ul> + * + * @param x the argument to <em>e</em><sup>x</sup> - 1. + * @return <em>e</em> raised to the power <code>x</code> minus one. + * @see #exp(double) + */ + public static double expm1(double x) + { + // Method + // 1. Argument reduction: + // Given x, find r and integer k such that + // + // x = k * ln(2) + r, |r| <= 0.5 * ln(2) + // + // Here a correction term c will be computed to compensate + // the error in r when rounded to a floating-point number. + // + // 2. Approximating expm1(r) by a special rational function on + // the interval [0, 0.5 * ln(2)]: + // Since + // r*(exp(r)+1)/(exp(r)-1) = 2 + r^2/6 - r^4/360 + ... + // we define R1(r*r) by + // r*(exp(r)+1)/(exp(r)-1) = 2 + r^2/6 * R1(r*r) + // That is, + // R1(r**2) = 6/r *((exp(r)+1)/(exp(r)-1) - 2/r) + // = 6/r * ( 1 + 2.0*(1/(exp(r)-1) - 1/r)) + // = 1 - r^2/60 + r^4/2520 - r^6/100800 + ... + // We use a special Remes algorithm on [0, 0.347] to generate + // a polynomial of degree 5 in r*r to approximate R1. The + // maximum error of this polynomial approximation is bounded + // by 2**-61. In other words, + // R1(z) ~ 1.0 + Q1*z + Q2*z**2 + Q3*z**3 + Q4*z**4 + Q5*z**5 + // where Q1 = -1.6666666666666567384E-2, + // Q2 = 3.9682539681370365873E-4, + // Q3 = -9.9206344733435987357E-6, + // Q4 = 2.5051361420808517002E-7, + // Q5 = -6.2843505682382617102E-9; + // (where z=r*r, and Q1 to Q5 are called EXPM1_Qx in the source) + // with error bounded by + // | 5 | -61 + // | 1.0+Q1*z+...+Q5*z - R1(z) | <= 2 + // | | + // + // expm1(r) = exp(r)-1 is then computed by the following + // specific way which minimize the accumulation rounding error: + // 2 3 + // r r [ 3 - (R1 + R1*r/2) ] + // expm1(r) = r + --- + --- * [--------------------] + // 2 2 [ 6 - r*(3 - R1*r/2) ] + // + // To compensate the error in the argument reduction, we use + // expm1(r+c) = expm1(r) + c + expm1(r)*c + // ~ expm1(r) + c + r*c + // Thus c+r*c will be added in as the correction terms for + // expm1(r+c). Now rearrange the term to avoid optimization + // screw up: + // ( 2 2 ) + // ({ ( r [ R1 - (3 - R1*r/2) ] ) } r ) + // expm1(r+c)~r - ({r*(--- * [--------------------]-c)-c} - --- ) + // ({ ( 2 [ 6 - r*(3 - R1*r/2) ] ) } 2 ) + // ( ) + // + // = r - E + // 3. Scale back to obtain expm1(x): + // From step 1, we have + // expm1(x) = either 2^k*[expm1(r)+1] - 1 + // = or 2^k*[expm1(r) + (1-2^-k)] + // 4. Implementation notes: + // (A). To save one multiplication, we scale the coefficient Qi + // to Qi*2^i, and replace z by (x^2)/2. + // (B). To achieve maximum accuracy, we compute expm1(x) by + // (i) if x < -56*ln2, return -1.0, (raise inexact if x!=inf) + // (ii) if k=0, return r-E + // (iii) if k=-1, return 0.5*(r-E)-0.5 + // (iv) if k=1 if r < -0.25, return 2*((r+0.5)- E) + // else return 1.0+2.0*(r-E); + // (v) if (k<-2||k>56) return 2^k(1-(E-r)) - 1 (or exp(x)-1) + // (vi) if k <= 20, return 2^k((1-2^-k)-(E-r)), else + // (vii) return 2^k(1-((E+2^-k)-r)) + + boolean negative = (x < 0); + double y, hi, lo, c, t, e, hxs, hfx, r1; + int k; + + long bits; + long h_bits; + long l_bits; + + c = 0.0; + y = abs(x); + + bits = Double.doubleToLongBits(y); + h_bits = getHighDWord(bits); + l_bits = getLowDWord(bits); + + // handle special cases and large arguments + if (h_bits >= 0x4043687aL) // if |x| >= 56 * ln(2) + { + if (h_bits >= 0x40862e42L) // if |x| >= EXP_LIMIT_H + { + if (h_bits >= 0x7ff00000L) + { + if (((h_bits & 0x000fffffL) | (l_bits & 0xffffffffL)) != 0) + return x; // exp(NaN) = NaN + else + return negative ? -1.0 : x; // exp({+-inf}) = {+inf, -1} + } + + if (x > EXP_LIMIT_H) + return Double.POSITIVE_INFINITY; // overflow + } + + if (negative) // x <= -56 * ln(2) + return -1.0; + } + + // argument reduction + if (h_bits > 0x3fd62e42L) // |x| > 0.5 * ln(2) + { + if (h_bits < 0x3ff0a2b2L) // |x| < 1.5 * ln(2) + { + if (negative) + { + hi = x + LN2_H; + lo = -LN2_L; + k = -1; + } + else + { + hi = x - LN2_H; + lo = LN2_L; + k = 1; + } + } + else + { + k = (int) (INV_LN2 * x + (negative ? - 0.5 : 0.5)); + t = k; + hi = x - t * LN2_H; + lo = t * LN2_L; + } + + x = hi - lo; + c = (hi - x) - lo; + + } + else if (h_bits < 0x3c900000L) // |x| < 2^-54 return x + return x; + else + k = 0; + + // x is now in primary range + hfx = 0.5 * x; + hxs = x * hfx; + r1 = 1.0 + hxs * (EXPM1_Q1 + + hxs * (EXPM1_Q2 + + hxs * (EXPM1_Q3 + + hxs * (EXPM1_Q4 + + hxs * EXPM1_Q5)))); + t = 3.0 - r1 * hfx; + e = hxs * ((r1 - t) / (6.0 - x * t)); + + if (k == 0) + { + return x - (x * e - hxs); // c == 0 + } + else + { + e = x * (e - c) - c; + e -= hxs; + + if (k == -1) + return 0.5 * (x - e) - 0.5; + + if (k == 1) + { + if (x < - 0.25) + return -2.0 * (e - (x + 0.5)); + else + return 1.0 + 2.0 * (x - e); + } + + if (k <= -2 || k > 56) // sufficient to return exp(x) - 1 + { + y = 1.0 - (e - x); + + bits = Double.doubleToLongBits(y); + h_bits = getHighDWord(bits); + l_bits = getLowDWord(bits); + + h_bits += (k << 20); // add k to y's exponent + + y = buildDouble(l_bits, h_bits); + + return y - 1.0; + } + + t = 1.0; + if (k < 20) + { + bits = Double.doubleToLongBits(t); + h_bits = 0x3ff00000L - (0x00200000L >> k); + l_bits = getLowDWord(bits); + + t = buildDouble(l_bits, h_bits); // t = 1 - 2^(-k) + y = t - (e - x); + + bits = Double.doubleToLongBits(y); + h_bits = getHighDWord(bits); + l_bits = getLowDWord(bits); + + h_bits += (k << 20); // add k to y's exponent + + y = buildDouble(l_bits, h_bits); + } + else + { + bits = Double.doubleToLongBits(t); + h_bits = (0x000003ffL - k) << 20; + l_bits = getLowDWord(bits); + + t = buildDouble(l_bits, h_bits); // t = 2^(-k) + + y = x - (e + t); + y += 1.0; + + bits = Double.doubleToLongBits(y); + h_bits = getHighDWord(bits); + l_bits = getLowDWord(bits); + + h_bits += (k << 20); // add k to y's exponent + + y = buildDouble(l_bits, h_bits); + } + } + + return y; + } + + /** * Take ln(a) (the natural log). The opposite of <code>exp()</code>. If the * argument is NaN or negative, the result is NaN; if the argument is * positive infinity, the result is positive infinity; and if the argument @@ -1429,6 +2052,33 @@ public final strictfp class StrictMath AT10 = 0.016285820115365782; // Long bits 0x3f90ad3ae322da11L. /** + * Constants for computing {@link #cbrt(double)}. + */ + private static final int + CBRT_B1 = 715094163, // B1 = (682-0.03306235651)*2**20 + CBRT_B2 = 696219795; // B2 = (664-0.03306235651)*2**20 + + /** + * Constants for computing {@link #cbrt(double)}. + */ + private static final double + CBRT_C = 5.42857142857142815906e-01, // Long bits 0x3fe15f15f15f15f1L + CBRT_D = -7.05306122448979611050e-01, // Long bits 0xbfe691de2532c834L + CBRT_E = 1.41428571428571436819e+00, // Long bits 0x3ff6a0ea0ea0ea0fL + CBRT_F = 1.60714285714285720630e+00, // Long bits 0x3ff9b6db6db6db6eL + CBRT_G = 3.57142857142857150787e-01; // Long bits 0x3fd6db6db6db6db7L + + /** + * Constants for computing {@link #expm1(double)} + */ + private static final double + EXPM1_Q1 = -3.33333333333331316428e-02, // Long bits 0xbfa11111111110f4L + EXPM1_Q2 = 1.58730158725481460165e-03, // Long bits 0x3f5a01a019fe5585L + EXPM1_Q3 = -7.93650757867487942473e-05, // Long bits 0xbf14ce199eaadbb7L + EXPM1_Q4 = 4.00821782732936239552e-06, // Long bits 0x3ed0cfca86e65239L + EXPM1_Q5 = -2.01099218183624371326e-07; // Long bits 0xbe8afdb76e09c32dL + + /** * Helper function for reducing an angle to a multiple of pi/2 within * [-pi/4, pi/4]. * diff --git a/java/lang/management/ManagementFactory.java b/java/lang/management/ManagementFactory.java index 2de6d3b05..6e7af0f27 100644 --- a/java/lang/management/ManagementFactory.java +++ b/java/lang/management/ManagementFactory.java @@ -52,6 +52,8 @@ import gnu.java.lang.management.ThreadMXBeanImpl; import java.util.ArrayList; import java.util.List; +import javax.management.NotCompliantMBeanException; + /** * <p> * Provides access to the system's management beans via a series @@ -117,7 +119,16 @@ public class ManagementFactory public static OperatingSystemMXBean getOperatingSystemMXBean() { if (osBean == null) - osBean = new OperatingSystemMXBeanImpl(); + try + { + osBean = new OperatingSystemMXBeanImpl(); + } + catch (NotCompliantMBeanException e) + { + throw new InternalError("The GNU implementation of the " + + "operating system bean is not a " + + "compliant management bean."); + } return osBean; } @@ -131,7 +142,16 @@ public class ManagementFactory public static RuntimeMXBean getRuntimeMXBean() { if (runtimeBean == null) - runtimeBean = new RuntimeMXBeanImpl(); + try + { + runtimeBean = new RuntimeMXBeanImpl(); + } + catch (NotCompliantMBeanException e) + { + throw new InternalError("The GNU implementation of the " + + "runtime bean is not a compliant " + + "management bean."); + } return runtimeBean; } @@ -145,7 +165,16 @@ public class ManagementFactory public static ClassLoadingMXBean getClassLoadingMXBean() { if (classLoadingBean == null) - classLoadingBean = new ClassLoadingMXBeanImpl(); + try + { + classLoadingBean = new ClassLoadingMXBeanImpl(); + } + catch (NotCompliantMBeanException e) + { + throw new InternalError("The GNU implementation of the " + + "class loading bean is not a " + + "compliant management bean."); + } return classLoadingBean; } @@ -159,7 +188,16 @@ public class ManagementFactory public static ThreadMXBean getThreadMXBean() { if (threadBean == null) - threadBean = new ThreadMXBeanImpl(); + try + { + threadBean = new ThreadMXBeanImpl(); + } + catch (NotCompliantMBeanException e) + { + throw new InternalError("The GNU implementation of the " + + "thread bean is not a compliant " + + "management bean."); + } return threadBean; } @@ -173,7 +211,16 @@ public class ManagementFactory public static MemoryMXBean getMemoryMXBean() { if (memoryBean == null) - memoryBean = new MemoryMXBeanImpl(); + try + { + memoryBean = new MemoryMXBeanImpl(); + } + catch (NotCompliantMBeanException e) + { + throw new InternalError("The GNU implementation of the " + + "memory bean is not a compliant " + + "management bean."); + } return memoryBean; } @@ -191,7 +238,16 @@ public class ManagementFactory { if (compilationBean == null && SystemProperties.getProperty("gnu.java.compiler.name") != null) - compilationBean = new CompilationMXBeanImpl(); + try + { + compilationBean = new CompilationMXBeanImpl(); + } + catch (NotCompliantMBeanException e) + { + throw new InternalError("The GNU implementation of the " + + "compilation bean is not a compliant " + + "management bean."); + } return compilationBean; } @@ -207,7 +263,16 @@ public class ManagementFactory List poolBeans = new ArrayList(); String[] names = VMManagementFactory.getMemoryPoolNames(); for (int a = 0; a < names.length; ++a) - poolBeans.add(new MemoryPoolMXBeanImpl(names[a])); + try + { + poolBeans.add(new MemoryPoolMXBeanImpl(names[a])); + } + catch (NotCompliantMBeanException e) + { + throw new InternalError("The GNU implementation of the " + + "memory pool bean, " + a + ", is " + + "not a compliant management bean."); + } return poolBeans; } @@ -223,8 +288,17 @@ public class ManagementFactory List managerBeans = new ArrayList(); String[] names = VMManagementFactory.getMemoryManagerNames(); for (int a = 0; a < names.length; ++a) - managerBeans.add(new MemoryManagerMXBeanImpl(names[a])); - managerBeans.add(getGarbageCollectorMXBeans()); + try + { + managerBeans.add(new MemoryManagerMXBeanImpl(names[a])); + } + catch (NotCompliantMBeanException e) + { + throw new InternalError("The GNU implementation of the " + + "memory manager bean, " + a + ", is " + + "not a compliant management bean."); + } + managerBeans.addAll(getGarbageCollectorMXBeans()); return managerBeans; } @@ -240,7 +314,17 @@ public class ManagementFactory List gcBeans = new ArrayList(); String[] names = VMManagementFactory.getGarbageCollectorNames(); for (int a = 0; a < names.length; ++a) - gcBeans.add(new GarbageCollectorMXBeanImpl(names[a])); + try + { + gcBeans.add(new GarbageCollectorMXBeanImpl(names[a])); + } + catch (NotCompliantMBeanException e) + { + throw new InternalError("The GNU implementation of the " + + "garbage collector bean, " + a + + ", is not a compliant management " + + "bean."); + } return gcBeans; } diff --git a/java/lang/management/MemoryMXBean.java b/java/lang/management/MemoryMXBean.java index 33d211c9b..4d9e5ff1c 100644 --- a/java/lang/management/MemoryMXBean.java +++ b/java/lang/management/MemoryMXBean.java @@ -70,6 +70,34 @@ package java.lang.management; * either change (either expanding or contracting) or stay * the same. * </p> + * <h2>Notifications</h2> + * <p> + * Implementations of this interface also conform to the + * {@link javax.management.NotificationEmitter} interface, + * and supply two notifications reflecting memory usage. + * These notifications occur when a usage threshold is + * exceeded; for more details of these, see the documentation + * of {@link MemoryPoolMXBean}. If threshold monitoring + * is supported, then a notification will be emitted each time + * the threshold is crossed. Another notification will not + * be emitted unless the usage level has dropped below the + * threshold again in the meantime. + * </p> + * <p> + * The emitted notifications are instances of + * {@link javax.management.Notification}, with a type of + * either + * {@link java.lang.management.MemoryNotificationInfo#MEMORY_THRESHOLD_EXCEEDED} + * or + * {@link java.lang.management.MemoryNotificationInfo#MEMORY_COLLECTION_THRESHOLD_EXCEEDED} + * (depending on whether the notification refers to the general + * usage threshold or the garbage collection threshold) and an instance + * of {@link java.lang.management.MemoryNotificationInfo} contained + * in the user data section. This is wrapped inside an instance + * of {@link javax.management.openmbean.CompositeData}, as explained + * in the documentation for + * {@link java.lang.management.MemoryNotificationInfo}. + * </p> * * @author Andrew John Hughes (gnu_andrew@member.fsf.org) * @since 1.5 diff --git a/java/lang/management/MemoryNotificationInfo.java b/java/lang/management/MemoryNotificationInfo.java new file mode 100644 index 000000000..adb38b06f --- /dev/null +++ b/java/lang/management/MemoryNotificationInfo.java @@ -0,0 +1,215 @@ +/* MemoryNotificationInfo.java - Emitted memory notification info. + Copyright (C) 2006 Free Software Foundation + +This file is part of GNU Classpath. + +GNU Classpath is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2, or (at your option) +any later version. + +GNU Classpath is distributed in the hope that it will be useful, but +WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +General Public License for more details. + +You should have received a copy of the GNU General Public License +along with GNU Classpath; see the file COPYING. If not, write to the +Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA +02110-1301 USA. + +Linking this library statically or dynamically with other modules is +making a combined work based on this library. Thus, the terms and +conditions of the GNU General Public License cover the whole +combination. + +As a special exception, the copyright holders of this library give you +permission to link this library with independent modules to produce an +executable, regardless of the license terms of these independent +modules, and to copy and distribute the resulting executable under +terms of your choice, provided that you also meet, for each linked +independent module, the terms and conditions of the license of that +module. An independent module is a module which is not derived from +or based on this library. If you modify this library, you may extend +this exception to your version of the library, but you are not +obligated to do so. If you do not wish to do so, delete this +exception statement from your version. */ + +package java.lang.management; + +import gnu.java.lang.management.MemoryMXBeanImpl; + +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.SimpleType; + +/** + * <p> + * Represents the content of a notification emitted by the + * {@link MemoryMXBean}. Such notifications are emitted when + * one of the memory pools exceeds its usage or collection + * usage threshold. This object contains the following information, + * representing the state of the pool at the time of the + * notification: + * </p> + * <ul> + * <li>The name of the pool.</li> + * <li>The memory usage of the pool at the time of notification.</li> + * <li>The number of times the pool has exceeded this particular + * threshold in the past.</li> + * </ul> + * <p> + * Two types of notification are emitted by the {@link MemoryMXBean}: + * one for exceeding the usage threshold and one for exceeding the + * collection usage threshold. The value returned by {@link #getCount()} + * is dependent on this type; if the threshold exceeded is the usage + * threshold, then the usage threshold count is returned. If, instead, + * the collection usage threshold is exceeded, then the collection usage + * threshold count is returned. + * </p> + * <p> + * This data is held in the user data part of the notification (returned + * by {@link javax.management.Notification#getUserData()}) encapsulated in + * a {@link javax.management.openmbean.CompositeData} object. The + * {@link #from(javax.management.openmbean.CompositeData)} method may be + * used to unwrap the value and obtain an instance of this class. + * </p> + * + * @author Andrew John Hughes (gnu_andrew@member.fsf.org) + * @since 1.5 + */ +public class MemoryNotificationInfo +{ + + /** + * The type of notification emitted when the usage threshold is exceeded. + * After a notification is emitted, the usage level must drop below the + * threshold again before another notification is emitted. The value is + * <code>java.management.memory.threshold.exceeded</code>. + */ + public static final String MEMORY_THRESHOLD_EXCEEDED = + "java.management.memory.threshold.exceeded"; + + /** + * The type of notification emitted when the collection usage threshold + * is exceeded, following a garbage collection cycle. The value is + * <code>java.management.memory.collection.threshold.exceeded</code>. + */ + public static final String MEMORY_COLLECTION_THRESHOLD_EXCEEDED = + "java.management.memory.collection.threshold.exceeded"; + + /** + * The name of the memory pool which exceeded the threshold. + */ + private String poolName; + + /** + * The usage level of the memory pool at the time of notification. + */ + private MemoryUsage usage; + + /** + * The number of times the threshold has been crossed. + */ + private long count; + + /** + * Constructs a new {@link MemoryNotificationInfo} object using the + * specified pool name, usage level and threshold crossing count. + * + * @param poolName the name of the pool which has exceeded a threshold. + * @param usage the usage level of the pool at the time of notification. + * @param count the number of times the threshold has been crossed. + */ + public MemoryNotificationInfo(String poolName, MemoryUsage usage, long count) + { + this.poolName = poolName; + this.usage = usage; + this.count = count; + } + + /** + * <p> + * Returns a {@link MemoryNotificationInfo} instance using the values + * given in the supplied + * {@link javax.management.openmbean.CompositeData} object. + * The composite data instance should contain the following + * attributes with the specified types: + * </p> + * <table> + * <th><td>Name</td><td>Type</td></th> + * <tr><td>poolName</td><td>java.lang.String</td></tr> + * <tr><td>usage</td><td>javax.management.openmbean.CompositeData + * </td></tr> + * <tr><td>count</td><td>java.lang.Long</td></tr> + * </table> + * <p> + * The usage level is further described as: + * </p> + * <table> + * <th><td>Name</td><td>Type</td></th> + * <tr><td>init</td><td>java.lang.Long</td></tr> + * <tr><td>used</td><td>java.lang.Long</td></tr> + * <tr><td>committed</td><td>java.lang.Long</td></tr> + * <tr><td>max</td><td>java.lang.Long</td></tr> + * </table> + * + * @param data the composite data structure to take values from. + * @return a new instance containing the values from the + * composite data structure, or <code>null</code> + * if the data structure was also <code>null</code>. + * @throws IllegalArgumentException if the composite data structure + * does not match the structure + * outlined above. + */ + public static MemoryNotificationInfo from(CompositeData data) + { + if (data == null) + return null; + CompositeType type = data.getCompositeType(); + ThreadInfo.checkAttribute(type, "poolName", SimpleType.STRING); + ThreadInfo.checkAttribute(type, "usage", MemoryMXBeanImpl.usageType); + ThreadInfo.checkAttribute(type, "count", SimpleType.LONG); + MemoryUsage usage = MemoryUsage.from((CompositeData) data.get("usage")); + return new MemoryNotificationInfo(((String) data.get("poolName")), + usage, + ((Long) data.get("count")).longValue()); + } + + /** + * Returns the number of times the memory pool has crossed the usage + * threshold, as of the time of notification. If this is the notification + * represented by the type {@link #MEMORY_THRESHOLD_EXCEEDED}, then the + * count is the usage threshold count. If this is the notification + * represented by the type {@link #MEMORY_COLLECTION_THRESHOLD_EXCEEDED}, + * then the count is the collection usage threshold count. + * + * @return the number of times the appropriate threshold has been crossed. + */ + public long getCount() + { + return count; + } + + /** + * Returns the name of the pool which has crossed a threshold. + * + * @return the name of the pool. + */ + public String getPoolName() + { + return poolName; + } + + /** + * Returns the usage levels at the time of notification. + * + * @return the usage levels. + */ + public MemoryUsage getUsage() + { + return usage; + } + +} + diff --git a/java/lang/management/MemoryPoolMXBean.java b/java/lang/management/MemoryPoolMXBean.java index 29b438c29..5b04c64d3 100644 --- a/java/lang/management/MemoryPoolMXBean.java +++ b/java/lang/management/MemoryPoolMXBean.java @@ -157,6 +157,14 @@ public interface MemoryPoolMXBean MemoryUsage getPeakUsage(); /** + * Returns the type of memory used by this pool. This can be + * either heap or non-heap memory. + * + * @return the type of this pool. + */ + String getType(); + + /** * Returns memory usage statistics for the current memory usage * of the pool. The return value may be <code>null</code> if * this pool is no longer valid. Obtaining these values is diff --git a/java/lang/management/MemoryUsage.java b/java/lang/management/MemoryUsage.java index 29aa1f9f1..3c2a4cba6 100644 --- a/java/lang/management/MemoryUsage.java +++ b/java/lang/management/MemoryUsage.java @@ -37,6 +37,9 @@ exception statement from your version. */ package java.lang.management; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.SimpleType; /** * <p> * Retains information on the usage of a particular memory @@ -146,6 +149,48 @@ public class MemoryUsage } /** + * <p> + * Returns a {@link MemoryUsage} instance using the values + * given in the supplied + * {@link javax.management.openmbean.CompositeData} object. + * The composite data instance should contain the following + * attributes: + * </p> + * <ul> + * <li>init</li> + * <li>used</li> + * <li>committed</li> + * <li>max</li> + * </ul> + * <p> + * All should have the type, <code>java.lang.Long</code>. + * </p> + * + * @param data the composite data structure to take values from. + * @return a new instance containing the values from the + * composite data structure, or <code>null</code> + * if the data structure was also <code>null</code>. + * @throws IllegalArgumentException if the composite data structure + * does not match the structure + * outlined above, or the values + * are invalid. + */ + public static MemoryUsage from(CompositeData data) + { + if (data == null) + return null; + CompositeType type = data.getCompositeType(); + ThreadInfo.checkAttribute(type, "init", SimpleType.LONG); + ThreadInfo.checkAttribute(type, "used", SimpleType.LONG); + ThreadInfo.checkAttribute(type, "committed", SimpleType.LONG); + ThreadInfo.checkAttribute(type, "max", SimpleType.LONG); + return new MemoryUsage(((Long) data.get("init")).longValue(), + ((Long) data.get("used")).longValue(), + ((Long) data.get("committed")).longValue(), + ((Long) data.get("max")).longValue()); + } + + /** * Returns the amount of memory committed for use by this * memory pool (in bytes). This amount is guaranteed to * be available, unlike the maximum. diff --git a/java/lang/management/ThreadInfo.java b/java/lang/management/ThreadInfo.java index ebb2e8382..4bf35a4cb 100644 --- a/java/lang/management/ThreadInfo.java +++ b/java/lang/management/ThreadInfo.java @@ -37,6 +37,13 @@ exception statement from your version. */ package java.lang.management; +import javax.management.openmbean.ArrayType; +import javax.management.openmbean.CompositeData; +import javax.management.openmbean.CompositeType; +import javax.management.openmbean.OpenDataException; +import javax.management.openmbean.OpenType; +import javax.management.openmbean.SimpleType; + /** * <p> * A class which maintains information about a particular @@ -83,9 +90,19 @@ public class ThreadInfo { /** - * The thread which this instance concerns. + * The id of the thread which this instance concerns. + */ + private long threadId; + + /** + * The name of the thread which this instance concerns. + */ + private String threadName; + + /** + * The state of the thread which this instance concerns. */ - private Thread thread; + private String threadState; /** * The number of times the thread has been blocked. @@ -100,17 +117,24 @@ public class ThreadInfo private long blockedTime; /** - * The monitor lock on which this thread is blocked - * (if any). + * The name of the monitor lock on which this thread + * is blocked (if any). */ - private Object lock; + private String lockName; /** - * The thread which owns the monitor lock on which this - * thread is blocked, or <code>null</code> if there is - * no owner. + * The id of the thread which owns the monitor lock on + * which this thread is blocked, or <code>-1</code> + * if there is no owner. */ - private Thread lockOwner; + private long lockOwnerId; + + /** + * The name of the thread which owns the monitor lock on + * which this thread is blocked, or <code>null</code> + * if there is no owner. + */ + private String lockOwnerName; /** * The number of times the thread has been in a waiting @@ -176,11 +200,60 @@ public class ThreadInfo long waitedTime, boolean isInNative, boolean isSuspended, StackTraceElement[] trace) { - this.thread = thread; + this(thread.getId(), thread.getName(), thread.getState(), blockedCount, + blockedTime, lock.getClass().getName() + "@" + + Integer.toHexString(System.identityHashCode(lock)), lockOwner.getId(), + lockOwner.getName(), waitedCount, waitedTime, isInNative, isSuspended, + trace); + } + + /** + * Constructs a new {@link ThreadInfo} corresponding + * to the thread details specified. + * + * @param threadId the id of the thread on which this + * new instance will be based. + * @param threadName the name of the thread on which + * this new instance will be based. + * @param threadState the state of the thread on which + * this new instance will be based. + * @param blockedCount the number of times the thread + * has been blocked. + * @param blockedTime the accumulated number of milliseconds + * the specified thread has been blocked + * (only used with contention monitoring enabled) + * @param lockName the name of the monitor lock the thread is waiting for + * (only used if blocked) + * @param lockOwnerId the id of the thread which owns the monitor + * lock, or <code>-1</code> if it doesn't have an owner + * (only used if blocked) + * @param lockOwnerName the name of the thread which owns the monitor + * lock, or <code>null</code> if it doesn't have an + * owner (only used if blocked) + * @param waitedCount the number of times the thread has been in a + * waiting state. + * @param waitedTime the accumulated number of milliseconds the + * specified thread has been waiting + * (only used with contention monitoring enabled) + * @param isInNative true if the thread is in a native method. + * @param isSuspended true if the thread is suspended. + * @param trace the stack trace of the thread to a pre-determined + * depth (see VMThreadMXBeanImpl) + */ + private ThreadInfo(long threadId, String threadName, String threadState, + long blockedCount, long blockedTime, String lockName, + long lockOwnerId, String lockOwnerName, long waitedCount, + long waitedTime, boolean isInNative, boolean isSuspended, + StackTraceElement[] trace) + { + this.threadId = threadId; + this.threadName = threadName; + this.threadState = threadState; this.blockedCount = blockedCount; this.blockedTime = blockedTime; - this.lock = lock; - this.lockOwner = lockOwner; + this.lockName = lockName; + this.lockOwnerId = lockOwnerId; + this.lockOwnerName = lockOwnerName; this.waitedCount = waitedCount; this.waitedTime = waitedTime; this.isInNative = isInNative; @@ -189,6 +262,145 @@ public class ThreadInfo } /** + * Checks for an attribute in a {@link CompositeData} structure + * with the correct type. + * + * @param ctype the composite data type to check. + * @param name the name of the attribute. + * @param type the type to check for. + * @throws IllegalArgumentException if the attribute is absent + * or of the wrong type. + */ + static void checkAttribute(CompositeType ctype, String name, + OpenType type) + throws IllegalArgumentException + { + OpenType foundType = ctype.getType(name); + if (foundType == null) + throw new IllegalArgumentException("Could not find a field named " + + name); + if (!(foundType.equals(type))) + throw new IllegalArgumentException("Field " + name + " is not of " + + "type " + type.getClassName()); + } + + /** + * <p> + * Returns a {@link ThreadInfo} instance using the values + * given in the supplied + * {@link javax.management.openmbean.CompositeData} object. + * The composite data instance should contain the following + * attributes with the specified types: + * </p> + * <table> + * <th><td>Name</td><td>Type</td></th> + * <tr><td>threadId</td><td>java.lang.Long</td></tr> + * <tr><td>threadName</td><td>java.lang.String</td></tr> + * <tr><td>threadState</td><td>java.lang.String</td></tr> + * <tr><td>suspended</td><td>java.lang.Boolean</td></tr> + * <tr><td>inNative</td><td>java.lang.Boolean</td></tr> + * <tr><td>blockedCount</td><td>java.lang.Long</td></tr> + * <tr><td>blockedTime</td><td>java.lang.Long</td></tr> + * <tr><td>waitedCount</td><td>java.lang.Long</td></tr> + * <tr><td>waitedTime</td><td>java.lang.Long</td></tr> + * <tr><td>lockName</td><td>java.lang.String</td></tr> + * <tr><td>lockOwnerId</td><td>java.lang.Long</td></tr> + * <tr><td>lockOwnerName</td><td>java.lang.String</td></tr> + * <tr><td>stackTrace</td><td>javax.management.openmbean.CompositeData[] + * </td></tr> + * </table> + * <p> + * The stack trace is further described as: + * </p> + * <table> + * <th><td>Name</td><td>Type</td></th> + * <tr><td>className</td><td>java.lang.String</td></tr> + * <tr><td>methodName</td><td>java.lang.String</td></tr> + * <tr><td>fileName</td><td>java.lang.String</td></tr> + * <tr><td>lineNumber</td><td>java.lang.Integer</td></tr> + * <tr><td>nativeMethod</td><td>java.lang.Boolean</td></tr> + * </table> + * + * @param data the composite data structure to take values from. + * @return a new instance containing the values from the + * composite data structure, or <code>null</code> + * if the data structure was also <code>null</code>. + * @throws IllegalArgumentException if the composite data structure + * does not match the structure + * outlined above. + */ + public static ThreadInfo from(CompositeData data) + { + if (data == null) + return null; + CompositeType type = data.getCompositeType(); + checkAttribute(type, "threadId", SimpleType.LONG); + checkAttribute(type, "threadName", SimpleType.STRING); + checkAttribute(type, "threadState", SimpleType.STRING); + checkAttribute(type, "suspended", SimpleType.BOOLEAN); + checkAttribute(type, "inNative", SimpleType.BOOLEAN); + checkAttribute(type, "blockedCount", SimpleType.LONG); + checkAttribute(type, "blockedTime", SimpleType.LONG); + checkAttribute(type, "waitedCount", SimpleType.LONG); + checkAttribute(type, "waitedTime", SimpleType.LONG); + checkAttribute(type, "lockName", SimpleType.STRING); + checkAttribute(type, "lockOwnerId", SimpleType.LONG); + checkAttribute(type, "lockOwnerName", SimpleType.STRING); + try + { + CompositeType seType = + new CompositeType(StackTraceElement.class.getName(), + "An element of a stack trace", + new String[] { "className", "methodName", + "fileName", "lineNumber", + "nativeMethod" + }, + new String[] { "Name of the class", + "Name of the method", + "Name of the source code file", + "Line number", + "True if this is a native method" + }, + new OpenType[] { + SimpleType.STRING, SimpleType.STRING, + SimpleType.STRING, SimpleType.INTEGER, + SimpleType.BOOLEAN + }); + checkAttribute(type, "stackTrace", new ArrayType(1, seType)); + } + catch (OpenDataException e) + { + throw new IllegalStateException("Something went wrong in creating " + + "the composite data type for the " + + "stack trace element.", e); + } + CompositeData[] dTraces = (CompositeData[]) data.get("stackTrace"); + StackTraceElement[] traces = new StackTraceElement[dTraces.length]; + for (int a = 0; a < dTraces.length; ++a) + /* FIXME: We can't use the boolean as there is no available + constructor. */ + traces[a] = + new StackTraceElement((String) dTraces[a].get("className"), + (String) dTraces[a].get("methodName"), + (String) dTraces[a].get("fileName"), + ((Integer) + dTraces[a].get("lineNumber")).intValue()); + return new ThreadInfo(((Long) data.get("threadId")).longValue(), + (String) data.get("threadName"), + (String) data.get("threadState"), + ((Long) data.get("blockedCount")).longValue(), + ((Long) data.get("blockedTime")).longValue(), + (String) data.get("lockName"), + ((Long) data.get("lockOwnerId")).longValue(), + (String) data.get("lockOwnerName"), + ((Long) data.get("waitedCount")).longValue(), + ((Long) data.get("waitedTime")).longValue(), + ((Boolean) data.get("inNative")).booleanValue(), + ((Boolean) data.get("suspended")).booleanValue(), + traces); + } + + /** * Returns the number of times this thread has been * in the {@link java.lang.Thread.State#BLOCKED} state. * A thread enters this state when it is waiting to @@ -272,10 +484,9 @@ public class ThreadInfo */ public String getLockName() { - if (thread.getState().equals("BLOCKED")) + if (threadState.equals("BLOCKED")) return null; - return lock.getClass().getName() + "@" + - Integer.toHexString(System.identityHashCode(lock)); + return lockName; } /** @@ -291,11 +502,9 @@ public class ThreadInfo */ public long getLockOwnerId() { - if (thread.getState().equals("BLOCKED")) - return -1; - if (lockOwner == null) + if (threadState.equals("BLOCKED")) return -1; - return lockOwner.getId(); + return lockOwnerId; } /** @@ -311,11 +520,9 @@ public class ThreadInfo */ public String getLockOwnerName() { - if (thread.getState().equals("BLOCKED")) - return null; - if (lockOwner == null) + if (threadState.equals("BLOCKED")) return null; - return lockOwner.getName(); + return lockOwnerName; } /** @@ -350,7 +557,7 @@ public class ThreadInfo */ public long getThreadId() { - return thread.getId(); + return threadId; } /** @@ -361,7 +568,7 @@ public class ThreadInfo */ public String getThreadName() { - return thread.getName(); + return threadName; } /** @@ -372,7 +579,7 @@ public class ThreadInfo */ public String getThreadState() { - return thread.getState(); + return threadState; } /** @@ -480,17 +687,17 @@ public class ThreadInfo */ public String toString() { - String state = thread.getState(); return getClass().getName() + - "[id=" + thread.getId() + - ", name=" + thread.getName() + - ", state=" + state + + "[id=" + threadId + + ", name=" + threadName + + ", state=" + threadState + ", blockedCount=" + blockedCount + ", waitedCount=" + waitedCount + ", isInNative=" + isInNative + ", isSuspended=" + isSuspended + - (state.equals("BLOCKED") ? ", lock=" + lock + - ", lockOwner=" + lockOwner : "") + + (threadState.equals("BLOCKED") ? + ", lockOwnerId=" + lockOwnerId + + ", lockOwnerName=" + lockOwnerName : "") + "]"; } |