JAVA STRINGS
STRINGS AND STRING
OPERATIONSOverview
• Creating String Objects
• Substring methods
• The Concatenation Operator
• Strings are Immutable
• Other Methods of the String Class
• Example using String Methods
CREATING STRING OBJECTS
Strings are Objects
• String is a sequence of characters enclosed in quotes. E.g. “Hello”
• String processing is one of the most important and most frequent applications of a
computer
• Java recognizes this fact and therefore provides special support for strings to make
their use convenient
• Every string is an instance of Java’s built in String class, thus, Strings are objects.
Declaration
• Like any object, a string can be created using new as in the following example:
String str1 = new String(“Hello dear”);
• However, as an extra support, Java allows String object to be created without the
use of new, as in:
String str2=”How are you”;
• This is inconsistent with the way Java treats other classes.
SUBSTRINGS
• String objects are represented as a sequence of characters indexed from 0.
Example: String greeting = “Hello, World”;
H e l l o , W o r l d !
0 1 2 3 4 5 6 7 8 9 10 11 12
• A common operation on Strings is extracting a substring from a a given string.
• Java provides two methods for this operation:
substring(start); Returns the substring from start to
the end of the string
substring(start, end); Returns a substring from start to end
but not including the character at
end.
Examples:
String sub = [Link](0, 4); “Hell”
String w = [Link](7, 12); “World”
String tail = [Link](7); “World!”
CONCATENATION OPERATOR
• Another common operation on String is concatenation.
• As another special support for String, Java overloaded the + operator to be used to
concatenate two String objects to get a bigger one.
String firstName = “Amr”;
String lastName = “Al-Ibrahim”;
String fullName = lastName+” “+firstName;
“Al-Ibrahim Amr”
• If one of the operands of the + operator is a string, the other is automatically
converted to string and the two strings are then concatenated.
String course = “ICS”;
int code = 102;
String courseCode = course+code “ICS102”
• We frequently use the concatenation operator in println statements.
[Link](“The area =“+area);
• You need to be careful with concatenation operator. For example, what do you this
the following print?
[Link](“Sum =“+5+6);
STRINGS ARE IMMUTABLE
• Another special feature of Strings is that they are immutable. That is, once a string
object is created, its content cannot be changed. For example, consider the
following:
String str1 = “Hello World”;
str1 = [Link](4);
• Instead of changing the str1 object, another object is created. The former is
garbage collected, thus, the reference to the former is lost.
• The fact that Strings are immutable allows the Java system to process Strings very
efficiently.
• For example, consider the following:
String str1 = “Hello”;
String str2 = “Hello”;
• We would expect the following
• But in fact, this is what happens
• The Java system is smart enough to know that the two strings are identical and
allocates same memory location for the two objects
METHODS OF THE STRING
CLASS
• In addition to the substring methods, several predefined methods are
provided in the built-in String class. Some of these are:
int length() returns the number of characters in this String
String toUpperCase() returns a new String, equivalent to the Upper/lower case of this String
String toLowerCase()
boolean equals(s) returns true if s the same as this String.
boolean
equalsIgnoreCase(s)
int compareTo(String s) returns +ve number, 0, or -ve number if this String is greater than, equal to or less
int than s.
compareToIngoreCase(s)
char charAt(index) returns the char in this String, at the index position.
int indexOf(ch) Returns the index of the first / last occurrence of ch in this string, If not fount-1 is
int lastIndexOf(ch) returned
String trim() returns a String, obtained by removing spaces from the start and end of this string.
static String valueOf (any Returns a String representation of the argument
primitive type)
String concat(s) equivalent to + symbol
EXAMPLE USING METHODS OF STRING CLASS
• The following program generates a password for a student using his
initials and age.
public class MakePassword {
public static void main(String[] args) {
String firstName = "Amr";
String middleName = "Samir";
String lastName = "Ibrahim";
//extract initials
String initials =
[Link](0,1)+
[Link](0,1)+
[Link](0,1);
//append age
int age = 20;
String password = [Link]()+age;
[Link]("Your Password ="+password);
}
}
STRINGBUFFER CLASS
• A thread-safe, mutable sequence of characters. A string buffer is like a String, but
can be modified. At any point in time it contains some particular sequence of
characters, but the length and content of the sequence can be changed through
certain method calls.
• String buffers are safe for use by multiple threads. The principal operations on a
StringBuffer are the append and insert methods. Each effectively converts a
given datum to a string and then appends or inserts the characters of that string
to the string buffer. The append method always adds these characters at the end
of the buffer; the insert method adds the characters at a specified point.
• For example, if z refers to a string buffer object whose current contents are
"start", then the method call [Link]("le") would cause the string buffer to
contain "startle", whereas [Link](4, "le") would alter the string buffer to contain
"starlet".
• In general, if sb refers to an instance of a StringBuffer, then [Link](x) has the
same effect as [Link]([Link](), x).
STRING BUFFER CONSTRUCTORS
Constructor and Description
StringBuffer()Constructs a string buffer with no characters in it and an
initial capacity of 16 characters.
StringBuffer(CharSequence seq)Constructs a string buffer that contains
the same characters as the specified CharSequence.
StringBuffer(int capacity)Constructs a string buffer with no characters in it
and the specified initial capacity.
StringBuffer(String str)Constructs a string buffer initialized to the contents
of the specified string.
import [Link].*;
class GFG {
public static void main(String[] args)
{
StringBuffer s = new StringBuffer(“Hello world");
[Link](5, 8, “oo");
[Link](s);
}
}
STRINGBUILDER CLASS
• StringBuilder objects are like String objects, except that they can be modified.
Hence Java StringBuilder class is also used to create mutable (modifiable) string
object. StringBuilder is same as StringBuffer except for one important difference.
StringBuilder is not synchronized, which means it is not thread safe. At any point,
the length and content of the sequence can be changed through method
invocations.
Constructors of StringBuilder class:
• StringBuilder ( ) : Constructs a string builder with no characters in it and an initial
capacity of 16 characters.
• StringBuilder ( int capacity ) : Constructs a string builder with no characters in it and
an initial capacity specified by the capacity argument.
• StringBuilder ( String str ) : Constructs a string builder initialized to the contents of
the specified string. The initial capacity of the string builder is 16 plus the length of
the string argument.
Methods of StringBuilder class
• append() : The append() method concatenates the given argument(string
representation) to the end of the invoking StringBuilder object. StringBuilder class
has several overloaded append() method. Few are:
– StringBuilder append(String str)
– StringBuilder append(int n)
– StringBuilder append(Object obj)
STRINGBUILDER CLASS
• insert() - The insert() method inserts the given argument(string representation) into the
invoking StringBuilder object at the given position.
• replace() - The replace() method replaces the string from specified start index to the end
index.
• reverse() - This method reverses the characters within a StringBuilder object.
• delete() - The delete() method of StringBuilder class deletes the string from the specified
beginIndex to endIndex.
• capacity() - The capacity() method returns the current capacity of StringBuilder object. The
capacity is the amount of storage available for newly inserted characters, beyond which an
allocation will occur.
No. StringBuffer StringBuilder
1) StringBuffer is synchronized i.e. thread safe. It means two StringBuilder is non-
threads can't call the methods of StringBuffer simultaneously. synchronized i.e. not thread safe.
It means two threads can call the
methods of StringBuilder
simultaneously.
2) StringBuffer is less efficient than StringBuilder. StringBuilder is more
efficient than StringBuffer.
JAVA THREADS
CONTENTS
1. What is a thread ?
2. Define and launch a thread
3. The life-cycle of a thread
4. interrupt a thread
5. thread synchronization
6. other issues
WHAT IS A THREAD ?
• A sequential (or single-threaded) program is one that, when executed, has only one
single flow of control.
– i.e., at any time instant, there is at most only one instruction (or statement or execution point)
that is being executed in the program.
• A multi-threaded program is one that can have multiple flows of control when executed.
– At some time instance, there may exist multiple instructions or execution points) that are being
executed in the program
– Ex: in a Web browser we may do the following tasks at the same time:
– 1. scroll a page,
– 2. download an applet or image,
– 3. play sound,
– 4 print a page.
• A thread is a single sequential flow of control within a program.
SINGLE-THREADED VS MULTITHREADED PROGRAMS
{ A();
newThreads {
{ A(); A1(); A2(); A3(); { A1(); A2(); A3() };
B1(); B2(); } {B1(); B2() }
}
}
THREAD ECOLOGY IN A JAVA
PROGRAM
started by java from main(String[])
started by main thread
started by B thread
lifetime of C thread
2. DEFINE AND LAUNCH A JAVA
THREAD
• Each Java Run time thread is encapsulated in a [Link] instance.
• Two ways to define a thread:
1. Extend the Thread class
2. Implement the Runnable interface :
package [Link];
public interface Runnable { public void run() ; }
• Steps for extending the Thread class:
1. Subclass the Thread class;
2. Override the default Thread method run(), which is the entry point of the thread, like the
main(String[]) method in a java program.
DEFINE A THREAD
// Example:
public class Print2Console extends Thread {
public void run() { // run() is to a thread what main() is to a java program
for (int b = -128; b < 128; b++) [Link](b); }
… // additional methods, fields …
}
• Impement the Runnable interface if you need a parent class:
// by extending JTextArea we can reuse all existing code of JTextArea
public class Print2GUI extend JTextArea implement Runnable {
public void run() {
for (int b = -128; b < 128; b++) append( [Link](b) + “\n” ); }
}
HOW TO LAUNCH A THREAD
1. create an instance of [ a subclass of ] of Thread, say thread.
1. Thread thread = new Print2Console();
2. Thread thread = new Thread( new Print2GUI( .. ) );
2. call its start() method, [Link]();. // note: not call run() !!
Ex:
– Printer2Console t1 = new Print2Console(); // t1 is a thread instance !
– [Link]() ; // this will start a new thread, which begins its execution by
calling [Link]()
– … // parent thread continue immediately here without waiting for the child
thread to complete its execution. cf: [Link]();
– Print2GUI jtext = new Print2GUI();
– Thread t2 = new Thread( jtext);
– [Link]();
– …
THE [Link]
CONSTRUCTORS
// Public Constructors
• Thread([ ThreadGroup group,] [ Runnable target, ]
[ String name ] );
– Instances :
– Thread();
– Thread(Runnable target);
– Thread(Runnable target, String name);
– Thread(String name);
– Thread(ThreadGroup group, Runnable target);
– Thread(ThreadGroup group, Runnable target, String name);
– Thread(ThreadGroup group, String name);
// name is a string used to identify the thread instance
// group is the thread group to which this thred belongs.
SOME THREAD PROPERTY ACCESS METHODS
• int getID() // every thread has a unique ID, since jdk1.5
• String getName(); setName(String)
– // get/set the name of the thread
• ThreadGroup getThreadGroup();
• int getPriority() ; setPriority(int) // thread has priority in [0, 31]
• [Link] getState() // return current state of this thread
• boolean isAlive()
– Tests if this thread has been started and has not yet died. .
• boolean isDaemon()
– Tests if this thread is a daemon thread.
• boolean isInterrupted()
– Tests whether this thread has been interrupted.
STATE METHODS FOR CURRENT THREAD ACCESSES
• static Thread currentThread()
– Returns a reference to the currently executing thread object.
• static boolean holdsLock(Object obj)
– Returns true if and only if the current thread holds the monitor lock on the specified
object.
• static boolean interrupted()
– Tests whether the current thread has been interrupted.
• static void sleep( [ long millis [, int nanos ]] )
– Causes the currently executing thread to sleep (cease execution) for the specified
time.
• static void yield()
– Causes the currently executing thread object to temporarily pause and allow other
threads to execute.
AN EXAMPLE
public class SimpleThread extends Thread {
public SimpleThread(String str) { super(str); }
public void run() {
for (int i = 0; i < 10; i++) {
[Link](i + " " + getName());
try { // at this point, current thread is ‘this’.
[Link]((long)([Link]() * 1000));
} catch (InterruptedException e) {}
}
[Link]("DONE! " + getName());
} }
MAIN PROGRAM
public class TwoThreadsTest {
public static void main (String[] args) {
new SimpleThread(“Thread1").start();
new SimpleThread(“Thread2").start(); }}
possible output:
0 Thread1 5 Thread1 DONE! Thread2
0 Thread2 5 Thread2 9 Thread1
1 Thread2 6 Thread2 DONE! Thread1
1 Thread1 6 Thread1
2 Thread1 7 Thread1
2 Thread2 7 Thread2
3 Thread2 8 Thread2
3 Thread1 9 Thread2
4 Thread1 8 Thread1
4 Thread2
3. THE LIFE CYCLE OF A JAVA
THREAD
New ( Runnable blocked/waiting ) * Runnable dead(terminated)
• sleep(long ms [,int ns])
• // sleep (ms + ns x 10–3) milliseconds and then continue
• [ IO ] blocked by synchronized method/block
– synchronized( obj ) { … } // synchronized statement
– synchronized m(… ) { … } // synchronized method
– // return to runnable if IO complete
• [Link]()
• // retrun to runnable by [Link]() or [Link]()
• join(long ms [,int ns])
• // Waits at most ms milliseconds plus ns nanoseconds for this thread to die.
3. THE STATES(LIFE CYCLE) OF A THREAD (JAVA 1.5)
public class Thread { .. // enum in 1.5 is a special class for finite type.
public static enum State { //use [Link] for referring to this nested
class
NEW, // after new Thread(), but before start().
RUNNABLE, // after start(), when running or ready
BLOCKED, // blocked by monitor lock
// blocked by a synchronized method/block
WAITING, // waiting for to be notified; no time out set
// wait(), join()
TIMED_WAITING, // waiting for to be notified; time out set
// sleep(time), wait(time), join(time)
TERMINATED // complete execution or after stop()
}…
}
The life cycle of a Java thread
runnable
get the lock blocked/waiting
start() resume()
new Thread(…)
not-running thread t terminates
(ready) sleep done
[Link](), [Link]()
interrupt()
(set bit) interrupt()
yield(), or
preempty scheduled
by OS (throw exception)
by OS
[Link]()
sleep(…)
running [Link]()
stop(),
terminated suspend()
run() exits
normally or blocked by lock
abnormally
STATE TRANSITION METHODS FOR THREAD
• public synchronized native void start() {
Note: When we call
– start a thread by calling its run() method …
[Link](), we in fact use
– It is illegal to start a thread more than once } current thread's time to
• public final void join( [long ms [, int ns]]); execute code of t thread
– Let current thread wait for receiver thread to die for at most ms+ns time
• static void yield() // callable by current thread only
– Causes the currently executing thread object to temporarily pause and
allow other threads to execute.
• public final void resume(); // deprecated
• public final void suspend();// deprecatedmay lead to deadlock
• public final void stop(); // deprecated lead to inconsistency
// state checking
• public boolean isAlive() ; // true if runnable or blocked
4. INTERRUPTING THREADS
• A blocking/waiting call (sleep(),wait() or join()) to a thread t can be
terminated by an InterruptedException thrown by invoking [Link]().
– this provides an alternative way to leave the blocked state.
– however, the control flow is different from the normal case.
Ex: public void run() {
try { … while (more work to do) { // Normal sleep() exit continue here
do some work;
sleep( … ); // give another thread a chance to work
}
}
catch (InterruptedException e) { // if waked-up by interrupt() then continue here
… // thread interrupted during sleep or wait }
}
• Note: the interrupt() method will not throw an InterruptedException if the
thread is not blocked/waiting. In such case the thread needs to call the static
interrupted() method to find out if it was recently interrupted. So we should
rewrite the while loop by
while ( ! interrupted() && moreWorkToDo() ) { … }
INTERRUPT-RELATED METHODS
• void interrupt()
– send an Interrupt request to a thread.
– the “interrupted” status of the thread is set to true.
– if the thread is blocked by sleep(), wait() or join(), the The interrupted status
of the thread is cleared and an InterruptedException is thrown.
– conclusion: runnable ==> “interrupted” bit set but no Exception thrown.
– not runnable ==> Exception thrown but “interrupted” bit not set
• static boolean interrupted() // destructive query
– Tests whether the current thread (self) has been interrupted.
– reset the “interrupted” status to false.
• boolean isInterrupted() // non-destructive query
– Tests whether this thread has been interrupted without changing the
“interrupted” status.
– may be used to query current executing thread or another non-executing
thread. e.g. if( [Link]() | [Link]()...) …
5. THREAD SYNCHRONIZATION
• Problem with any multithreaded Java program :
– Two or more Thread objects access the same pieces
of data.
• too little or no synchronization ==> there is
inconsistency, loss or corruption of data.
• too much synchronization ==> deadlock or system
frozen.
• In between there is unfair processing where several
threads can starve another one hogging all resources
between themselves.
MULTITHREADING MAY INCUR INCONSISTENCY : AN
EXAMPLE
Two concurrent deposits of 50 into an account with 0 initial
balance.:
void deposit(int amount) {
int x = [Link]();
x += amount;
[Link](x); }
deposit(50) : // deposit 2
• deposit(50) : // deposit 1
x = [Link]() //1 x = [Link]() //4
x += 50; //2 x += 50; //5
[Link](x) //3 [Link](x) //6
The execution sequence:
1,4,2,5,3,6 will result in unwanted result !!
Final balance is 50 instead of 100!!
SYNCHRONIZED METHODS AND STATEMENTS
• multithreading can lead to racing hazards where different orders of
interleaving produce different results of computation.
– Order of interleaving is generally unpredictable and is not
determined by the programmer.
• Java’s synchronized method (as well as synchronized statement) can
prevent its body from being interleaved by relevant methods.
– synchronized( obj ) { … } // synchronized statement with obj as
lock
– synchronized … m(… ) {… } //synchronized method with this as
lock
– When one thread executes (the body of) a synchronized
method/statement, all other threads are excluded from executing
any synchronized method with the same object as lock.
SYNCHRONIZING THREADS
• Java use the monitor concept to achieve mutual exclusion and synchronization between
threads.
• Synchronized methods /statements guarantee mutual exclusion.
– Mutual exclusion may cause a thread to be unable to complete its task. So monitor
allow a thread to wait until state change and then continue its work.
• wait(), notify() and notifyAll() control the synchronization of threads.
– Allow one thread to wait for a condition (logical state) and another to set it and then
notify waiting threads.
– condition variables => instance boolean variables
– wait => wait();
– notifying => notify(); notifyAll();
TYPICAL USAGE
synchronized void doWhenCondition() {
while ( !condition )
wait(); // wait until someone notifies us of changes in condition
… // do what needs to be done when condition is true
}
synchronized void changeCondition {
// change some values used in condition test
notify(); // Let waiting threads know something changed
}
Note: A method may serve both roles; it may need some condition to occur to do
something and its action my cause condition to change.
PRODUCER/CONSUMER PROBLEM
• Two threads: producer and consumer, one monitor: CubbyHole
• The Producer :
– generates a pair of integers between 0 and 9 (inclusive), stores it
in a CubbyHole object, and prints the sum of each generated
pair.
– sleeps for a random amount of time between 0 and 100
milliseconds before repeating the number generating cycle:
• The Consumer,
– consumes all pairs of integers from the CubbyHole as quickly as
they become available.
[Link]
public class Producer extends Thread {
private CubbyHole cubbyhole; private int id;
public Producer(CubbyHole c, int id) {
cubbyhole = c; [Link] = id; }
public void run() {
for (int i = 0; i < 10; i++)
for(int j =0; j < 10; j++ ) {
[Link](i, j);
[Link]("Producer #" + [Link] + " put: ("+i +","+j + ").");
try { sleep((int)([Link]() * 100)); }
catch (InterruptedException e) { }
};
}
}
[Link]
public class Consumer extends Thread {
private CubbyHole cubbyhole;
private int id;
public Consumer(CubbyHole c, int id) {
cubbyhole = c; [Link] = id; }
public void run() {
int value = 0;
for (int i = 0; i < 10; i++) {
value = [Link]();
[Link]("Consumer #" + [Link]
+ " got: " + value);
} }}
CUBBYHOLE WITHOUT MUTUAL
EXCLUSION
public class CubbyHole { private int x,y;
public synchronized int get() { return x+y; }
public synchronized void put(int i, int j) {x= i; y = j } }
Problem : data inconsistency for some possible execution sequence
– Suppose after put(1,9) the data is correct , i.e., (x,y) = (1,9)
– And then two method calls get() and put(2,0) try to access CubbyHole concurrently =>
possible inconsistent result:
– (1,9) get() { return x + y ; } { return 1 + y ; }
– (1,9) put(2,0) {x = 2; y = 0;} (x,y) = (2,0)
– (2,0) get() { return 1 + y ;} return 1 + 0 = return 1 (instead of 10!)
• By marking get() and put() as synchronized method, the
inconsistent result cannot occur since, by definition, when either
method is in execution by one thread, no other thread can execute
any synchronized method with this CubbyHole object as lock.
THE CUBBYHOLE
CUBBYHOLE WITHOUT SYNCHRONIZATION
public class CubbyHole {
private int x,y;
public synchronized int get() { return x+y; }
public synchronized void put(int i, int j) { x= i ; y = j; }
}
Problems:
1. Consumer quicker than Producer : some data got more than
once.
2. producer quicker than consumer: some put data not used by
consumer. Consumer #1 got: 3
ex: Producer #1 put: (0,4) Producer #1 put: (0,4)
Consumer #1 got: 4 Producer #1 put: (0,5)
Consumer #1 got: 4 Consumer #1 got: 5
Producer #1 put: (0,5)
ANOTHER CUBBYHOLE IMPLEMENTATION (STILL
INCORRECT!)
pubic class CubbyHole { int x,y; boolean available = false;
public synchronized int get() { // won't work!
if (available == true) {
available = false; return x+y;
} } // compilation error!! must return a value in any case!!
public synchronized void put(int a, int b) { // won't work!
if (available == false) {
available = true; x=a;y=b;
} }} // but how about the case that availeable == true ?
• put(..); get(); get(); // 2nd get() must return something!
• put(..);put(..); // 2nd put() has no effect!
[Link]
A
public class CubbyHole {
private int x,y; private boolean available = false; // condition var
public synchronized int get() {
while (available == false) {
try { [Link](); } catch (InterruptedException e) { } }
available = false; // enforce consumers to wait again.
notifyAll(); // notify all producer/consumer to compete for execution!
// use notify() if just wanting to wakeup one waiting thread!
return x+y; }
public synchronized void put(int a, int b) {
while (available == true) {
try { wait(); } catch (InterruptedException e) { } }
x= a; y = b;
available = true; // wake up waiting consumer/producer to continue
notifyAll(); // or notify(); }}
THE MAIN CLASS
public class ProducerConsumerTest {
public static void main(String[] args) {
CubbyHole c = new CubbyHole();
Producer p1 = new Producer(c, 1);
Consumer c1 = new Consumer(c, 1);
[Link]();
[Link]();
} }
OTHER ISSUES
• Thread priorities
– public final int getPriority();
– public final void setPriority();
– get/set priority bttween MIN_PRIORITY and MAX_PRIORITY
– default priority : NORMAL_PRIORITY
• Daemon threads:
– isDaemon(), setDaemon(boolean)
– A Daemon thread is one that exists for service of other threads.
– The JVM exits if all threads in it are Daemon threads.
– setDaemon(.) must be called before the thread is started.
• public static boolean holdsLock(Object obj)
– check if this thread holds the lock on obj.
– ex: synchronized( e ) { [Link](e) ? true:false // is true … }
THREAD GROUPS
• Every Java thread is a member of a thread group.
• Thread groups provide a mechanism for collecting multiple threads into a
single object and manipulating those threads all at once, rather than
individually.
• When creating a thread,
– let the runtime system put the new thread in some reasonable default group ( the
current thread group) or
– explicitly set the new thread's group.
• you cannot move a thread to a new group after the thread has been created.
– when launched, main program thread belongs to main thread group.
CREATING A THREAD EXPLICITLY IN A GROUP
public Thread(ThreadGroup group, Runnable runnable)
public Thread(ThreadGroup group, String name)
public Thread(ThreadGroup group, Runnable runnable, String name)
ThreadGroup myThreadGroup = new ThreadGroup(
"My Group of Threads");
Thread myThread = new Thread(myThreadGroup,
"a thread for my group");
• Getting a Thread's Group
theGroup = [Link]();
THE THREADGROUP CLASS
Collection Management Methods:
public class EnumerateTest {
public void listCurrentThreads() {
ThreadGroup currentGroup =
[Link]().getThreadGroup();
int numThreads = [Link]();
Thread[] listOfThreads = new Thread[numThreads];
[Link](listOfThreads);
for (int i = 0; i < numThreads; i++)
[Link]("Thread #" + i + " = " +
listOfThreads[i].getName());
}
}
METHODS THAT OPERATE ON THE THREADGROUP
• getMaxPriority(), setMaxPriority(int)
• isDaemon(), setDaemon(boolean)
– A Daemon thread group is one that destroys itself when its last thread/group
is destroyed.
• getName() // name of the thread
• getParent() and parentOf(ThreadGroup) // boolean
• toString()
• activeCount(), activeGroupCount()
• // # of active descendent threads, and groups
• suspend(); //deprecated; suspend all threads in this group.
• resume();
• stop();