Last updated 2004-06-28 by Roedy
Green ©1996-2004 Canadian Mind Products
Java definitions: 0-9 A B C D E F G H I J K L M N O P Q R S T U V W X Y Z
You are here : home : Java Glossary : T words : Thread.
Threads may be implemented by the JVM as native OS threads or as green threads. Microsoft's term for green threads is fibers. Multiple green threads are simulated threads using one native thread. Green threads can't take advantage of multiple CPUs, but they have the advantage of lighter weight for context switching.
Natural Bridge uses a hybrid of green and native which allows scalability to thousands of threads. An early Solaris Java had green threads. Pretty well the rest of thread implementations are native. You, as application programmer, have no way, in pure Java, to control which kind of threads are used.
Threads that work in the background to support the runtime environment are called daemon threads. For example, the clock handler thread, the idle thread, the screen updater thread, and the garbage collector thread are all daemon threads. The virtual machine exits whenever all non-daemon threads have completed. The daemon threads are then all automatically stopped when the JVM shuts down.
Some collections such as Vector and Hashtable are thread-safe, where ArrayList and HashMap are not. You can safely work with thread-safe collections simultaneously from two different threads, adding and looking up elements. You cannot with the others. The AWT is thread-safe; Swing is not. Thread safe code is usually slower, so you don't make code thread safe unless necessary.
If you want a task to be run at some time in the future or repeatedly at regular intervals, you can schedule it with the java.util.Timer class. This is more efficient than spawning separate sleeping threads yourself. Timer uses one Thread to track the entire schedule.
/** * A class that can be run on a new Thead */ public class InParallel implements Runnable { /** * Method that gets called when your thread starts. It does * whatever you want to happen in parallel. */ public void run() { System.out.println( "hello world from a separate thread" ); ... } }
The run method gets executed on a separate thread. When run returns, the thread dies, and cannot be revived or restarted. Don't call a Runnable's run method directly. If you do, you will not start a new Thread; you will just run the method in the ordinary way on the current thread. You must use start which creates a new thread and then calls run for you. To start the new thread you need some code like this:
// execute InParellel.run() // in parallel to this thread on a new thread. Thread t = new Thread ( new InParallel()); // Note we call t.start(), not t.run() // t.run() would just call run in the ordinary way. t.start();
Don't forget to set your thread variable (t in the example above) to null when you no longer need it. You don't have to wait till the thread terminates. If you don't, you will end up with a useless dead Thread object cluttering your heap.
There is another technique where you extend the Thread class and override its run method, but it is not as flexible.
ThreadLocal is a technique of providing per-thread variables that without having to build them into the Thread object. Roughly speaking it makes a static variable into an automatically managed array, one slot per each active thread.
try { // put current thread to sleep Thread.sleep( delayInMilliseconds ); } catch ( InterruptedException e ) { System.out.println( "some other thread woke me prematurely." ) }
// Bump up a thread's priority to the cpu // one notch above the usual. thread.setPriority( Thread.NORM_PRIORITY + 1 ); // Drop up the thread's priority two notches below // where it is now. thread.setPriority( thread.getPriority() - 2 );
Threads of equal priority are not necessarily scheduled round-robin style. One Thread can hog the CPU indefinitely squeezing out all the other Threads of equal priority even if the Threads call yield every once in a while to give the other Threads of equal priority a kick at the cat.
You may starve Swing so it never gets a chance to paint anything, even if you are on a separate Thread.
// Get reference to the thread running this // code right now. Thread runningNow = Thread.currentThread();
public void doDeposit ( int deposit ) { // Prevent two threads from updating the bank balance // at once. The fetch, addition, and store must be done // as one atomic unit, otherwise the bankBalance could get // out of whack. // Contention for this chuck of code // is resolved by locking the current object. // Any other critical code synchronized on this will also be locked // out when any thread is executing inside this critical region on this object. // I.e. there is one lock per object, not one per critical region. synchronized ( this ) { bankBalance += deposit; } } // When you want the whole routine synchronized on this // you can use the shorthand: public synchronized void doDeposit ( int deposit ) { bankBalance += deposit; }
The lock part of every Object is called the monitor.
Note that the exact same critical code section may be executing simultaneously so long as it locks on different objects. You don't always lock on this.
Because synchronized blocks can be nested, it is possible for thread to lock multiple objects at once. Then you have the potential for deadlock. If thread a has object 1 locked and wants object 2, and thread b has object 2 locked and wants object 1, they will stare at each other, waiting indefinitely in a Mexican standoff, sometimes called a deadly embrace. One way to avoid this is to always lock your objects is the same canonical order, always 1 before 2 using some convention you concoct to determine the standard order.
If you wanted two different critical sections to be able to execute simultaneously on the same object, to maximise speed in a multi-cpu machine or in critical sections that do i/o, you would need to create an auxiliary dummy locking object appended to (referenced by) the main object for the second critical region to use for its synchronized lock object, typically of type Object.
Once you understand these basics, you can go on to more complex tasks like co-operating producer-consumer threads that wait on each other and ways of allowing simultaneous read of a structure but only single-thread update.
Further, any variables that more than one thread might be changing have to be marked volatile to warn other threads to always look for a fresh copy of the value rather than relying on a their own cached copy.
![]() | Concurrent Programming in Java: Design Principles and Patterns | ||||||
| 0-201-69581-2 | |||||||
| Doug Lea | |||||||
| 339 pages. You can read it online. | |||||||
| |||||||
With wait, you first must gain a lock on an object with synchronized, then you check if you really need to wait. If you do, then you you call Object.wait() on the lock object. This puts your Thread to sleep, and releases the lock so that other threads might have it. Eventually some other thread awakens you from your slumber by calling Object.notify() or Object.notifyAll() on the lock object. You wake up then get in line waiting the reacquire the lock. When you finally do, you continue execution. In other words, you wait for some other thread to complete some work and notify you when it is done. The notifier thread needs to own the lock to be able to call notify, and it must release the lock before any of the waiting threads will be able to resume.
Most of the time in all this, the object is not kept locked. It is only locked for short periods to check if waiting is really necessary and do the wait or notify.
You might say that synchronized in for updating related groups of fields, where volatile is for updating independent single fields.
Particularly in a multi-cpu situation, you have a problem with caching. Each CPU keeps copies of variables in registers and in various hardware RAM caches. If another CPU changes a variable, it may automatically refresh the other CPUs' caches, but it certainly won't automatically refresh any other CPU's registers. This means a CPU may be using a stale copy of a variable's value and not know it. When you declare a variable volatile it warns the compiler to generate code to fetch the value freshly from RAM every time it is needed, even if it already has a copy it has not recently changed itself sitting in a register. Further, it warns the compiler to generate code to store the value into RAM every time it is changed so that other threads will immediately see the new value.
The same problem happens with less frequency in a single CPU system since each thread has its own virtual set of registers.
Despite what you may read elsewhere, volatile is not sufficient to make x++ into an atomic operation. Patricia Shanahan proved this experimentally. atomic means indivisible, not high-powered. Even with if x were declared Volatile, the thread will not necessarily get to complete the load, add, store in one operation without some other thread meddling with the x variable.
I have heard conflicting stories on just how synchronized and volatile mesh. It is safe to use them together: a volatile reference in a synchronized block. Some say you can use synchronized without volatile, but not volatile without synchronized in at least one of the threads. Others say you can use volatile on its own as well.
It seems to me, you would be safest to declare any variable examined by different threads as volatile whether you do all access inside synchronized or not. However, this is probably belt and suspenders, and might generate unecessarily slow code. If I were designing the system, volatile would only be needed when there is some unsynchronized access. Experiments are not enough. That determines behaviour with only one compiler-JVM combination. Someday I will wade through the specs to find out how these keywords are supposed to work.
I presume when you enter a synchronized block the compiler freshly loads all values it needs, and when you exit it makes sure all are stored so that other CPUs can see the new value. While it is inside the block it need not treat all variables as automatically volatile, since no other critical code is running. If someone can confirm or refute this assumption, please let me know.
Working with unsynchronized volatile data is very difficult to get solidly right. Treat it with just as much caution as you would unprotected volatile variables in a multi-threaded C or assembly language program. Reserve it for these few situations:
The problem is misuse of these features creates very subtle bugs that may not show up for days, or only when run on certain machines. You really do need a deep understanding of this, something I do not have yet. Unfortunately, trying to escape learning by being overly conservative also imparts a big speed penalty.
boolean onSwingThread = SwingUtilities. isEventDispatchThread();
to tell when you are on the Swing thread. You are not on it when main first starts up!
Sun now recommends that everything GUI either be on the event thread or called with invokeLater, including instantiating your initial JFrame.
The AWT equivalents are called java.awt.EventQueue.invokeLater() and EventQueue.invokeAndWait()
![]() | Java Threads, Second Edition | ||||||
| 1-56592-418-5 | |||||||
| Scott Oaks, Henry Wong | |||||||
| An introductory book with good examples. Not as deep as you would usually expect from O'Reilly. | |||||||
| |||||||
![]() | Thinking in java | ||||||
| 0-13-659723-8 | |||||||
| Bruce Eckel | |||||||
| read online. Has a chapter on threads. | |||||||
| |||||||
![]() | Java Thread Programming | ||||||
| 0-672-31585-8 | |||||||
| Paul Hyde | |||||||
| |||||||
![]() | Taming Java Threads | ||||||
| 1-893115-10-0 | |||||||
| Allen Holub | |||||||
| |||||||
home |
Canadian Mind Products | |||
| mindprod.com IP:[24.87.56.253] | ||||
| Your IP:[80.134.30.163] | ||||
| You are visitor number 7238. | ||||
| Please send errors, omissions and suggestions | ||||
| to improve this page to Roedy Green. | ||||
| You can get a fresh copy of this page from: | or possibly from your local J: drive mirror: | |||
| http://mindprod.com/jgloss/thread.html | J:\mindprod\jgloss\thread.html | |||