There are two ways to create your own thread type: subclass java.lang.Thread class, or implementing java.lang.Runnable and pass it to Thread constructor or java.util.concurrent.ThreadFactory. What is the difference, and which one is better?
1, The practical reason is, a Java class can have only one superclass. So if your thread class extends java.lang.Thread, it cannot inherit from any other classes. This limits how you can reuse your application logic.
2, From a design point of view, there should be a clean separation between how a task is identified and defined, between how it is executed. The former is the responsibility of a Runnalbe impl, and the latter is job of the Thread class.
3, A Runnable instance can be passed to other libraries that accept task submission, e.g., java.util.concurrent.Executors. A Thread subclass inherits all the overhead of thread management and is hard to reuse.
4, Their instances also have different lifecycle. Once a thread is started and completed its work, it's subject to garbage collection. An instance of Runnalbe task can be resubmitted or retried multiple times, though usually new tasks are instantiated for each submission to ease state management.
Monday, 26 December 2011
Extend Thread vs implement Runnable
Tuesday, 21 June 2011
Handling Interrupts
threadObject.interrupt();
In order for the interrupt to work, the thread object has to support interruption, i.e. The thread object should check for interruptions periodically, as shown below:
while(!interrupted()) {
doWork();
}
An interrupt does not force the thread to halt (except when the thread is in sleep or wait mode). As shown in the above piece of code, the thread has to check if it is interrupted and take appropriate action (most likely, cleanup and stop execution). There are two ways in which a thread can check if it is interrupted.
- isInterrupted(): This is a non-static method that simply checks whether a thread is interrupted, and returns true or false.
- interrupted(): This method (used in the above example) is a static method of the Thread class, which checks if the current thread is interrupted and clears the interrupted state of the thread.
Note: The interrupted state of a thread can be cleaned only by the that thread, no thread can clear the interrupted state of another thread.
While interrupting a thread does not affect it's normal execution (unless the thread is programmed to do so), a thread can also be interrupted by an InterruptedException thrown by the sleep or wait methods. This has to be handled in a proper way, since a thrown exception clears the interrupted state of the thread. InterruptedException is best handled in the following way:
try {
// do some work.
Thread.sleep(sleepTime);
}catch(InterruptedException e) {
Thread.currentThread().interrupt();
}
The question arises, is when and how should interruptions be handled. Here are some general tips handling interruptions:
- If the thread invokes methods that throw InterruptedException frequently, then it is better to catch the interrupted exception and set the interrupted state of the thread as shown above.
- If your method blocks, it should respond to interruption, otherwise you must decide what interruption/cancellation means for your method, and make such behavior a part of your method's contract. In general, any method that performs a blocking operation (directly or indirectly), should allow that blocking operation to be cancelled with interrupt and should throw an appropriate exception (as sleep and wait do). If you're using channels, available with the new I/O API introduced in Java 1.4, the blocked thread will get a ClosedByInterruptException exception.
- Never hide an interrupt by clearing it explicitly or by catching an InterruptedException and continuing normally as it prevents any thread from being cancellable when executing your code.
Saturday, 18 June 2011
Access Restriction Methods in ThreadGroup
The ThreadGroup class itself does not impose any access restrictions, such as allowing threads from one group to inspect or modify threads in a different group. Rather the Thread and ThreadGroup classes cooperate with security managers (subclasses of the SecurityManager class), which can impose access restrictions based on thread group membership.
The Thread and ThreadGroup class both have a method, checkAccess, which calls the current security manager's checkAccess method. The security manager decides whether to allow the access based on the group membership of the threads involved. If access is not allowed, the checkAccess method throws a SecurityException. Otherwise, checkAccess simply returns.
The following is a list of ThreadGroup methods that call ThreadGroup's checkAccess before performing the action of the method. These are what are known as regulated accesses, that is, accesses that must be approved by the security manager before they can be completed.
ThreadGroup(ThreadGroup parent, String name)setDaemon(boolean isDaemon)setMaxPriority(int maxPriority)stopsuspendresumedestroy
checkAccess before proceeding: - constructors that specify a thread group
stopsuspendresumesetPriority(int priority)setName(String name)setDaemon(boolean isDaemon)
SecurityManager, overriding the appropriate methods, and installing the SecurityManager as the current security manager in your application. For information about implementing a security manager, see the lesson Providing Your Own Security Manager. The HotJava Web browser is an example of an application that implements its own security manager. HotJava needs to ensure that applets are well-behaved and don't do nasty things to other applets running at the same time (such as lowering the priority of another applet's threads). HotJava's security manager does not allow threads in different groups to modify one another. Please note that access restrictions based on thread groups may vary from browser to browser and thus applets may behave differently in different browsers.
Methods that Operate on All Threads within a Group
The ThreadGroup class has three methods that allow you to modify the current state of all the threads within that group:
resumestopsuspend
ThreadGroup : Methods that Operate on the Group
ThreadGroup class supports several attributes that are set and retrieved from the group as a whole. These attributes include the maximum priority that any thread within the group can have, whether the group is a "daemon" group, the name of the group, and the parent of the group. The methods that get and set ThreadGroup attributes operate at the group level. They inspect or change the attribute on the ThreadGroup object, but do not affect any of the threads within the group. The following is a list of ThreadGroup methods that operate at the group level:
getMaxPriorityandsetMaxPrioritygetDaemonandsetDaemongetNamegetParentandparentOftoString
setMaxPriority to change a group's maximum priority, you are only changing the attribute on the group object; you are not changing the priority of any of the threads within the group. Consider the following program that creates a group and a thread within that group: public class MaxPriorityTest {
public static void main(String[] args) {
ThreadGroup groupNORM = new ThreadGroup(
"A group with normal priority");
Thread priorityMAX = new Thread(groupNORM,
"A thread with maximum priority");
// set Thread's priority to max (10)
priorityMAX.setPriority(Thread.MAX_PRIORITY);
// set ThreadGroup's max priority to normal (5)
groupNORM.setMaxPriority(Thread.NORM_PRIORITY);
System.out.println("Group's maximum priority = " +
groupNORM.getMaxPriority());
System.out.println("Thread's priority = " +
priorityMAX.getPriority());
}
}
ThreadGroup groupNORM is created, it inherits its maximum priority attribute from its parent thread group. In this case, the parent group priority is the maximum (MAX_PRIORITY) allowed by the Java runtime system. Next the program sets the priority of the priorityMAX thread to the maximum allowed by the Java runtime system. Then the program lowers the group's maximum to the normal priority (NORM_PRIORITY). The setMaxPriority method does not affect the priority of the priorityMAX thread, so that at this point, the priorityMAX thread has a priority of 10, which is greater than the maximum priority of its group, groupNORM. This is the output from the program: Group's maximum priority = 5As you can see a thread can have a higher priority than the maximum allowed by its group as long as the thread's priority is set before the group's maximum priority is lowered. A thread group's maximum priority is used to limit a thread's priority when the thread is first created within a group or when you use
Thread's priority = 10
setPriority to change the thread's priority. Note that setMaxPriority does change the maximum priority of all of its descendant-threadgroups. Similarly, a group's daemon status applies only to the group. Changing a group's daemon status does not affect the daemon status of any of the threads in the group. Furthermore, a group's daemon status does not in any way imply the daemon status of its threads--you can put any thread within a daemon thread group. The daemon status of a thread group simply indicates that the group will be destroyed when all of its threads have been terminated.
Collection Management Methods in ThreadGroup
ThreadGroup provides a set of methods that manage the threads and subgroups within the group and allow other objects to query the ThreadGroup for information about its contents. For example, you can call ThreadGroup's activeCount method to find out the number of active threads currently in the group. The activeCount method is often used with the enumerate method to get an array filled with references to all the active threads in a ThreadGroup. For example, the listCurrentThreads method in the following example fills an array with all of the active threads in the current thread group and prints their names: public class EnumerateTest {
public void listCurrentThreads() {
ThreadGroup currentGroup = Thread.currentThread().getThreadGroup();
int numThreads = currentGroup.activeCount();
Thread[] listOfThreads = new Thread[numThreads];
currentGroup.enumerate(listOfThreads);
for (int i = 0; i < numThreads; i++)
System.out.println("Thread #" + i + " = " +
listOfThreads[i].getName());
}
}
Other collection management methods provided by the ThreadGroup class include activeGroupCount and list.
Thursday, 9 June 2011
ThreadPools
Thread pooling refers to a technique where a pool of worker threads is created and managed by the application. When a new job arrives, instead of creating a new thread to service it, it's queued by the thread-pool manager and dispatched later to one of the available worker threads. The thread-pool manager manages the number of active worker threads based on available resources as well as load considerations, adding new threads to the pool or freeing some worker threads in response to the number of outstanding requests. The primary goals of thread pooling are managing the number of active threads in the system and reducing the overhead of creating new threads by reusing threads from a pool.
Pool Management
Various management methods exist for the pools. You can shutdown() the pool, which will reject any future submissions but complete processing of in-process executions and even those that had not yet started but were submitted before the shutdown was initiated. You can also more aggressively perform a shutdownNow(). This will also prevent any future submissions, but it has a few different, notable behaviours. It will not start execution of submitted but unstarted tasks. They will be in the returned list. It will also attempt to stop, or more precisely, Thread.interrupt() currently executing tasks. This is a best effort with no guarantee that these tasks will be successfully interrupted.
- A thread pool implementation is provided as instance of ExecutorService class,
- you can put in different implementations of BlockingQueue to specify different queue behavior such as queue bounds or priority ordering
Implementation of Thread Pools via ExecutorService
Implementation of Thread Pool via Executor Service is shown here.
Implementation of ThreadPools via BlockingQueue
Implementation of Thread Pools via BlockingQueue is shown here.
Benefits of Thread Pooling
- It saves the machine work of creating a new thread.
- Single thread can recycle again and again.
- The size of thread pool is given in starting .We can expand on the designs presented in this chapter to include a method to support growing the size of the pool at runtime if you need this kind of dynamic tuning.
- Response time can be quick.
Risks of using thread pools
- High Rejection rate - Suppose if an task is rejected because the thread pool is empty. There will be high rejection rate.Or if task on wait state then waiting time would be too long. Sometime there is problem of deadlock also.
- Contention - If you have a very large memory, and threads equivalent to that, you are contending the threads, though you have resources. So there threadlocal will be a good idea to use.
Tuesday, 31 May 2011
Thread Local in java
Thread Local can be considered as a scope of access, like a request scope or session scope. It’s a thread scope. It has following:
- Values stored in Thread Local are global to the thread, meaning that they can be accessed from anywhere inside that thread. If a thread calls methods from several classes, then all the methods can see the Thread Local variable set by other methods (because they are executing in same thread). The value need not be passed explicitly. It’s like how you use global variables.
- Values stored in Thread Local are local to the thread, meaning that each thread will have it’s own Thread Local variable. One thread can not access/modify other thread’s Thread Local variables.
Comparing Thread locals in other languages and Java
A thread-local variable effectively provides a separate copy of its value for each thread that uses it. Each thread can see only the value associated with that thread, and is unaware that other threads may be using or modifying their own copies. Some compilers (such as the Microsoft Visual C++ compiler or the IBM XL FORTRAN compiler) have incorporated support for thread-local variables into the language using a storage-class modifier (like static or volatile). Java compilers offer no special language support for thread-local variables; instead, they are implemented with the ThreadLocal class, which has special support in the core Thread class.
Because thread-local variables are implemented through a class, rather than as part of the Java language itself, the syntax for using thread-local variables is a bit more clumsy than for language dialects where thread-local variables are built in. To create a thread-local variable, you instantiate an object of class ThreadLocal. The ThreadLocal class behaves much like the various Reference classes in java.lang.ref; it acts as an indirect handle for storing or retrieving a value.
When to use ThreadLocal?
Consider a case when some application is connecting to database. Now you may provide some DAO with connection object as field:
class MyDao{
Connection con;
public void doSomeBusinessLogic()
{
con = datasource.getConnection();
con.doUpdate();
}
}
public synchronized void doBusinessLogic()
{
Connection con = datasource.getConnection();
//some logic
//do update
con.close();
}
- We have to create connection object each time method is called, which is very expensive.
- Also as threads increase, high processor usage will result. So this may result in problem.
Solution 2 : Make a connection pool and get connections from there.
public synchronized void doBusinessLogic(){
Connection con = pool.getConnection();
//some logic
//do update
}
This approach is fine. But still there is problem of contention. If you are using multi-threaded environment, with multicores, it will be waste of resources to use Connection pooling approach.
Solution 3 : Use thread local
Now we can use ThreadLocal to avoid contention.
Suppose we have thread T1 and T2. ThreadLocal for T1 has a map in which it will have T1 and corresponding connection object. Similarilty ThreadLocal for T2 has T2 and corresponding connection object. Now when doing the same business logic, we can say:
public void doBusinessLogic(){
Connection con = myThreadLocal.connection;
con.doUpdate();
}
So we don't have to create the connection object again and again. Also if hardware is good there is no contention on the database. Suppose later we need some other local variable say transaction, even that will be saved in the map like this.
Some people say that we can pass connection as parameter in the business method, but that will make code look horrible and cumbersome. But that is a solution.
Advantage of ThreadLocal:
- No contention. If memory is not an issue, thread local is the best approach.
- It avoids using local objects like connection to be used as parameter, making code look simpler but still efficient.
Example code
Consider you have a Servlet which calls some business methods. You have a requirement to generate a unique transaction id for each and every request this servlet process and you need to pass this transaction id to the business methods, for logging purpose. One solution would be passing this transaction id as a parameter to all the business methods as discussed above. But this is not a good solution as the code is redundant and unnecessary.
To solve that, you can use Thread Local. You can generate a transaction id (either in servlet or better in a filter) and set it in the Thread Local. After this, what ever the business method, that this servlet calls, can access the transaction id from the thread local.
This servlet might be servicing more that one request at a time. Since each request is processed in separate thread, the transaction id will be unique to each thread (local) and will be accessible from all over the thread’s execution (global).
Java provides an ThreadLocal object using which you can set/get thread scoped variables. Below is a code example demonstrating what I’d explained above.
First make the DAO or transaction dealing class:
package com.vaani.dao;
public class SomeDAO {
private String transactionId = null;
//some methods to deal with transaction
public void setTransactionId(String transId)
{
transactionId = transId;
}
public String getTransactionId() {
return transactionId;
}
}
Now create Thread Local class to hold this Dao above.
package com.vaani.threadlocal;In the above code, you are creating a ThreadLocal object as a static field which can be used by rest of the code to set/get thread local variables.
import com.vaani.dao.SomeDAO;
public class MyThreadLocal {
public static final ThreadLocal userThreadLocal
= new ThreadLocal();
public static void set(SomeDAO dao) {
userThreadLocal.set(dao);
}
public static void unset() {
userThreadLocal.remove();
}
public static SomeDAO get() {
return (SomeDAO)userThreadLocal.get();
}
}
Let’s create our main class file which will generate and set the transaction ID in thread local and then call the business method.
package com.vaani.demo;
import com.vaani.businesscode.BusinessService;
import com.vaani.dao.SomeDAO;
import com.vaani.threadlocal.MyThreadLocal;
public class ThreadLocalDemo extends Thread {
public static void main(String args[]) {
Thread threadOne = new ThreadLocalDemo();
threadOne.start();
Thread threadTwo = new ThreadLocalDemo();
threadTwo.start();
}
@Override
public void run() {
// sample code to simulate transaction id
SomeDAO dao = new SomeDAO();
dao.setTransactionId(getName());
// set the context object in thread local
// to access it somewhere else
MyThreadLocal.set(dao);
/* note that we are not explicitly
passing the transaction id */
new BusinessService().businessMethod();
MyThreadLocal.unset();
}
}
Finally, here’s the code for the BusinessService.java which will read from thread local and use the value.
package com.vaani.businesscode;
import com.vaani.dao.SomeDAO;
import com.vaani.threadlocal.MyThreadLocal;
public class BusinessService {
public void businessMethod() {
// get the context from thread local
SomeDAO dao = MyThreadLocal.get();
System.out.println(dao.getTransactionId());
}
}
Output
When you run the ThreadLocalDemo file, you’ll get the below output:
Thread-1
Thread-0
As you might see, even though we are not explicitly passing the transaction id, the value can be accessed from the business method and printed on the console. Adding to it, the transaction ID differs for each thread (0 and 1).
Source Code
You can download Source code from here.
Monday, 30 May 2011
How to synchronize a static variable of a class ?
There are some ways(3 to my knowledge, but may be more), by which a static variable can be synchronized in java.
1) Use a synchronized static method. This synchronizes on the class object.
public class Counter {
private static int count = 0;
public static synchronized void incrementCount() {
count++;
}
}
2) Explicitly synchronize on the class object, using synchronize on ClassName.class
public class Counter {
private static int count = 0;
public void incrementCount() {
synchronize (Test.class) {
count++;
}
}
}
3) Synchronize on some other static object.
public class Counter {
private static int count = 0;
private static final Object countLockHelper = new Object();
public void incrementCount() {
synchronize (countLockHelper) {
count++;
}
}
}
Method 3 is best in many cases because the lock object is not exposed outside of your class. So if you create instance of these class, they will be synchronized on the same static object.
But if you just using some basic type like integer here in case of counter, consider using an AtomicInteger or another suitable class from the java.util.concurrent.atomic package:
public class Counter {
private final static AtomicInteger count = new AtomicInteger(0);
public void incrementCount() {
count.incrementAndGet();
}
}
Thursday, 26 May 2011
The ThreadGroup class in java
ThreadGroup class manages groups of threads for Java applications. A ThreadGroup can contain any number of threads. The threads in a group are generally related in some way, such as who created them, what function they perform, or when they should be started and stopped. ThreadGroups can contain not only threads but also other ThreadGroups. The top-most thread group in a Java application is the thread group named main. You can create threads and thread groups in the main group. You can also create threads and thread groups in subgroups of main. The result is a root-like hierarchy of threads and thread groups:
The ThreadGroup class has methods that can be categorized as follows:
- Collection Management Methods--Methods that manage the collection of threads and subgroups contained in the thread group.
- Methods That Operate on the Group--These methods set or get attributes of the
ThreadGroupobject. - Methods That Operate on All Threads within a Group--This is a set of methods that perform some operation, such as start or resume, on all the threads and subgroups within the
ThreadGroup. - Access Restriction Methods--
ThreadGroupandThreadallow the security manager to restrict access to threads based on group membership.
Process vs threads
- Process: A process runs independently and isolated of other processes. It cannot directly access shared data in other processes. The resources of the process are allocated to it via the operating system, e.g. memory and CPU time.
- Threads: threads are so called lightweight processes which have their own call stack but an access shared data. Every thread has its own memory cache. If a thread reads shared data it stores this data in its own memory cache. A thread can re-read the shared data, when this happens in Java will be explained in Java memory model part of this article.
Tuesday, 24 May 2011
Java shutdown hooks
Java allows you to add shutdown hooks to your code. A shutdown hook is simply a thread that has been left in the initialized state. When your JVM is about to shutdown, the shutdown hook thread kicks in. The finalization processes of java objects run after the shutdown hooks complete. The JVM allows you to register more than one shutdown hook.
public class Task
{
public static void main(String[] args)
{
Runtime runtime = Runtime.getRuntime();
Thread thread = new Thread(new ShutDownListener());
runtime.addShutdownHook(thread);
someProcess();
}
private static void someProcess()
{
try
{
System.out.println("I am busy");
Thread.sleep(2000);
}
catch (InterruptedException e)
{
e.printStackTrace();
}
}
}
class ShutDownListener implements Runnable
{
@Override
public void run()
{
System.out.println("I am shutting down");
}
}
The Task class is a simple class that runs a process. Once this process finishes up, we want the JVM to run a shutdown hook to notify us that the JVM is shutting down. When this program is run, the output is
I am busy
I am shutting down
The shutdown hook still executes. So the hook will execute even if there are errors / exceptions in the main program. What happens when the hook itself throws an error / exception ?. The uncaught exception will by default be printed to System.err and propagated to the VM. The behavior is comparable to a thread encountering an uncaught exception.
It seems pretty robust. However the shutdown hook is not guaranteed to execute. If a user closes the app abruptly or the VM crashes, or you click on the little red button on the eclipse console view, the shutdown hook will not run. It is not a good idea to use a shutdown hook to release critical resources (I have seen some code snippets that do this). It might end up not running and cause damage. The shutdown hook will execute only on normal termination or orderly shutdown.
Use the shutdown hook if you would like to do trivial operations with it. You can write code inside the hook that can clean up after the program (say delete a temporary file). Or write a bye bye message. The code inside the hook should not do critical things like release DB connections that your program acquired. Doing something like that is asking for trouble, since this code may never run.
Also keep in mind that hooks run concurrently. Each hook is registered as a Thread with the VM and each Thread will run in parallel with the other hooks. If the hooks synchronize over resources incorrectly you will end up dead locking the application.
The hooks also need to finish up quickly. If they do not, that poses a problem. The application will wait for ever to exit gracefully.
So now you know what shutdown hooks are and how to use them, if you ever need to.
In Summary
- Do not write shutdown hooks to do critical tasks
- Make sure your shut down hooks complete quickly
- Consider using one shutdown hook instead of several. If you decide to use several shutdown hooks, make their activities thread safe.
- Hook code flow should not depend on the method in which the application was shutdown. How an application terminates is never guaranteed.
Sunday, 1 May 2011
SingleThreadModel
If a servlet implements the SingleThreadModel interface, then the servlet container may create multiple instances of the servlet so as to handle heavy request load. Here, all request will still be serialized to a single instance only.
This is event true for a distibutable application. I mean that if the application is distributable and its servlets implement SingleThreadModel interface then also the above described behaviour may happen internaly. The only difference will be that there will be multiple instances of servlet per VM.
Note: Multiple VM's run on each machines in case of distributable application.
Saturday, 30 April 2011
Class level lock vs instance level lock
A class level lock is the lock which makes all object of a class to wait until the corresponding lock is not released.
e.g
Class A{
static synchronized void foo(){}
}Here the method foo is synchronized and hence all the threads on all the objects of the class will wait until the object currently running the foo method completes its execution.
Similarly an instance level lock makes all the threads started using the instance of the class to wait until the lock is not released.
e.g.
Class A{
//static is missing
synchronized void bar(){}
}Here all the threads started from the object which is currently executing the bar method will wait until the current threads completes its execution. Note that other threads of other objects can execute the bar method while another object's thread is executing the bar method.
What is the difference between yield and sleep method?
Yield:
1) It causes the high priority threads to pause execution and give the low priority threads a chance to execute.
2) The thread going into waiting queue because of yield method release any locks held by them.
Sleep:
1) It causes the thread on which it is invoked to go into waiting state for some time interval.
2) The thread going into waiting queue because of yield method doesn't release any locks held by it.
About Daemon Threads in Java
There can be two types of threads in Java viz User Thread and Daemon Thread. All the threads created by a user are user threads. A thread becomes Daemon thread when the user says so. User threads are meant for the program code.
On the other hand Daemon threads are service provider threads. They should not be used to run your program code but some system code. The run() method for a daemon thread is typically an infinite loop that waits for a service request. These threads run in parallel to your code but survive on the mercy of the JVM. When JVM finds no user threads it stops and all daemon threads are terminated instantly. Thus one should never rely on daemon code to perform any program code.
For better understanding consider a well known example of Daemon thread : Java garbage collector. The Garbage collector runs as a low priority daemon thread to reclaim any unused memory. When all user threads terminates, JVM may stop and garbage collector also terminates instantly.
Daemon threads are typically used to perform services for your application/applet. The core difference between user threads and daemon threads is that the JVM will only shut down a program when all user threads have terminated. Daemon threads are terminated by the JVM when there are no longer any user threads running, including the main thread of execution. Use daemons as the minions they are. This makes sense because when only daemon threads remain, there is no other thread for which a daemon thread can provide a service.
To specify that a thread is a daemon thread, call the setDaemon() method with the argument true. To determine if a thread is a daemon thread, use the accessor method isDaemon().
Thursday, 23 September 2010
Threads in java
What Is a Thread?
A thread--sometimes called an execution context or a lightweight process--is a single sequential flow of control within a program. You use threads to isolate tasks. When you run one of these sorting applets, it creates a thread that performs the sort operation. Each thread is a sequential flow of control within the same program (the browser). Each sort operation runs independently from the others, but at the same time.
Customizing a Thread's run Method
First, you need to get a thread to do something by providing the run method for a thread. This section shows you two different ways to do this. The Life Cycle of a Thread
Once you know how to get a thread to do something, you need to understand the life cycle of a Thread Understanding Thread Priority
A thread's priority affects when it runs in relation to other threads. This section talks about how this affects your programs.
Synchronizing Threads
The first sample programs in this lesson use either one thread or multiple threads that run asynchronously. However, it is often useful to use multiple threads that share data and therefore must synchronize their activities. In this section you will learn how to synchronize threads and how to avoid problems such as starvation and deadlock.
Grouping Threads
This section shows you how to group threads and what you can do with a group of threads.
Summary
When you've completed this lesson on threads, you will have toured the intricacies of Java threads including the life cycle of a Java thread (as represented by its state), scheduling, thread groups, and synchronization. The Java development environment supports multithreaded programs through the language, the libraries, and the runtime system. This summary page highlights the features in the Java development environment that support threads and gives you links to further documentation about those features.
Summary of threads
Package Support of Threads
java.lang.Thread![]()
- In the Java development enviroment, threads are objects that derive from java.lang's
Threadclass. TheThreadclass defines and implements Java threads. You can subclass theThreadclass to provide your own thread implementations or you can use theRunnableinterface.java.lang.Runnable![]()
- The Java language library also defines the
Runnableinterface, which allows any class to provide the body (therunmethod) for a thread.java.lang.Object![]()
- The root class,
Object, defines three methods you can use to synchronize methods around a condition variable:wait,notify, andnotifyAll.java.lang.ThreadGroup![]()
- All threads belong to a thread group, which typically contains related threads. The
ThreadGroupclass in thejava.langpackage implements groups of threads.java.lang.ThreadDeath- A thread is normally killed by throwing a
ThreadDeathobject at it. Rarely, a thread might need to catchThreadDeathto clean up before it dies.
Language Support of Threads
The Java language has two keywords related to the synchronization of threads:volatile(which is not implemented in JDK 1.0) andsynchronized. Both of these language features help ensure the integrity of data that is shared between two concurrently running threads. Multithreaded Programs discusses thread synchronization issues.
Runtime Support of Threads
The Java runtime system contains the scheduler, which is responsible for running all the existing threads. The Java scheduler uses a fixed priority scheduling algorithm which boils down to this simple rule of thumb:
Rule of thumb: At any given time, the highest priority thread is running. However, this is not guaranteed. The thread scheduler may choose to run a lower priority thread to avoid starvation. For this reason, use priority only to affect scheduling policy for efficiency purposes. Do not rely on thread priority for algorithm correctness.
Other Thread Information
- Threads in Applets
- When you write applets that use threads, you may have to make special provisions, such as ensuring that your applet is well-behaved. Also, some browsers impose security restrictions for applets based on which thread group a thread is in.
Grouping Threads
ThreadGroupjava.lang package. The runtime system puts a thread into a thread group during thread construction. When you create a thread, you can either allow the runtime system to put the new thread in some reasonable default group or you can explicitly set the new thread's group. The thread is a permanent member of whatever thread group it joins upon its creation--you cannot move a thread to a new group after the thread has been created.
The Default Thread Group
If you create a new Thread without specifying its group in the constructor, the runtime system automatically places the new thread in the same group as the thread that created it (known as the current thread group and the current thread, respectively). So, if you leave the thread group unspecified when you create your thread, what group contains your thread? When a Java application first starts up, the Java runtime system creates aThreadGroupnamedmain. Unless specified otherwise, all new threads that you create become members of themainthread group.
Note: If you create a thread within an applet, the new thread's group may be something other thanmain, depending on the browser or viewer that the applet is running in. Refer to Threads in Applets for information about thread groups in applets.
Many Java programmers ignore thread groups altogether and allow the runtime system to handle all of the details regarding thread groups. However, if your program creates a lot of threads that should be manipulated as a group, or if you are implementing a custom security manager, you will likely want more control over thread groups. Continue reading for more details!
Creating a Thread Explicitly in a Group
As mentioned previously, a thread is a permanent member of whatever thread group it joins when its created--you cannot move a thread to a new group after the thread has been created. Thus, if you wish to put your new thread in a thread group other than the default, you must specify the thread group explicitly when you create the thread. TheThreadclass has three constructors that let you set a new thread's group:Each of these constructors creates a new thread, initializes it based on thepublic Thread(ThreadGroup group, Runnable target)
public Thread(ThreadGroup group, String name)
public Thread(ThreadGroup group, Runnable target, String name)RunnableandStringparameters, and makes the new thread a member of the specified group. For example, the following code sample creates a thread group (myThreadGroup) and then creates a thread (myThread) in that group.TheThreadGroup myThreadGroup = new ThreadGroup("My Group of Threads");
Thread myThread = new Thread(myThreadGroup, "a thread for my group");ThreadGrouppassed into aThreadconstructor does not necessarily have to be a group that you create--it can be a group created by the Java runtime system, or a group created by the application in which your applet is running.
Getting a Thread's Group
To find out what group a thread is in, you can call itsgetThreadGroupmethod:theGroup = myThread.getThreadGroup();
The ThreadGroup Class
Once you've obtained a thread's ThreadGroup, you can query the group for information, such as what other threads are in the group. You can also modify the threads in that group, such as suspending, resuming, or stopping them, with a single method invocation. Avoiding Starvation and Deadlock
The story goes like this: Five philosophers are sitting at a round table. In front of each philosopher is a bowl of rice. Between each pair of philosophers is one chopstick. Before an individual philosopher can take a bite of rice he must have two chopsticks--one taken from the left, and one taken from the right. The philosophers must find some way to share chopsticks such that they all get to eat.
The following applet does a rough animation using an image of Duke for the dining philosophers. This particular algorithm works as follows: Duke always reaches for the chopstick on his right first. If the chopstick is there, Duke takes it and raises his right hand. Next, Duke tries for the left chopstick. If the chopstick is available, Duke picks it up and raises his other hand. Now that Duke has both chopsticks, he takes a bite of rice and says "Mmm!" He then puts both chopsticks down, allowing either of his two neighbors to get the chopsticks. Duke then starts all over again by trying for the right chopstick. Between each attempt to grab a chopstick, each Duke pauses for a random period of time.
The slider controls the amount of time that each philosopher will wait before attempting to pick up a chopstick. When the slider is set to 0, the philosophers don't wait--they just grab--and the applet ends up in deadlock: all the philosophers are frozen with their right hand in the air. Why? Because each philosopher immediately has one chopstick and is waiting on a condition that cannot be satisfied--they are all waiting for the left chopstick, which is held by the philosopher to their left.
When you move the slider so that the waiting period is longer, the applet may proceed for a while without deadlocking. However, deadlock is always possible with this particular implementation of the dining philosophers problem because it is possible for all five philosophers to be holding their right chopsticks. Rather than rely on luck to prevent deadlock, you must either prevent it or detect it.
For most Java programmers, the best choice is to prevent deadlock rather than to try and detect it. Deadlock detection is complicated and beyond the scope of this tutorial. The simplest approach to to preventing deadlock is to impose ordering on the condition variables. In the dining philosopher applet, there is no ordering imposed on the condition variables because the philosophers and the chopsticks are arranged in a circle. All chopsticks are equal.
However, we can change the rules in the applet by numbering the chopsticks 1 through 5 and insisting that the philosophers pick up the chopstick with the lower number first. The philosopher who is sitting between chopsticks 1 and 2 and the philosopher who is sitting between chopsticks 1 and 5 must now reach for the same chopstick first (chopstick 1) rather than picking up the one on the right. Whoever gets chopstick 1 first is now free to take another one. Whoever doesn't get chopstick 1 must now wait for the first philosopher to release it. Deadlock is not possible.