OutOfMemoryError - why can a waiting Thread not be garbage collected? - java

This simple sample code demonstrates the problem. I create an ArrayBlockingQueue, and a thread that waits for data on this queue using take(). After the loop is over, in theory both the queue and the thread can be garbage collected, but in practice I soon get an OutOfMemoryError. What is preventing this to be GC'd, and how can this be fixed?
/**
* Produces out of memory exception because the thread cannot be garbage
* collected.
*/
#Test
public void checkLeak() {
int count = 0;
while (true) {
// just a simple demo, not useful code.
final ArrayBlockingQueue<Integer> abq = new ArrayBlockingQueue<Integer>(2);
final Thread t = new Thread(new Runnable() {
#Override
public void run() {
try {
abq.take();
} catch (final InterruptedException e) {
e.printStackTrace();
}
}
});
t.start();
// perform a GC once in a while
if (++count % 1000 == 0) {
System.out.println("gc");
// this should remove all the previously created queues and threads
// but it does not
System.gc();
}
}
}
I am using Java 1.6.0.
UPDATE: perform GC after a few iterations, but this does not help.

Threads are top level objects. They are 'special' so they do not follow the same rules as other objects. The do not rely on references to keep them 'alive' (i.e. safe from GC). A thread will not get garbage collected until it has ended. Which doesn't happen in your sample code, since the thread is blocked. Of course, now that the thread object is not garbage collected, then any other object referenced by it (the queue in your case) also cannot be garbage collected.

You are creating threads indefinitely because they all block until ArrayBlockingQueue<Integer> abq has some entry. So eventually you'll get a OutOfMemoryError.
(edit)
Each thread you create will never end because it blocks until the abq queue as one entry.
If the thread is running, the GC isn't going to collect any object that the thread is referencing including the queue abq and the thread itself.

abq.put(0);
should save your day.
Your threads all wait on their queue's take() but you never put anything in those queues.

Your while loop is an infinite loop and its creating new threads continuously. Although you starting the thread execution as soon as its created but the time its taking to complete the task by the thread is greater then the time its taking to create the thread.
Also what are doing with the abq parameter by declaring it inside the while loop?
Based on your edits and other comments. System.gc() doesn't not guarantee a GC cycle. Read my statement above the speed of execution of your thread is lower than the speed of creation.
I checked the comment for the take() method "Retrieves and removes the head of this queue, waiting if no elements are present on this queue." I see you define the ArrayBlockingQueue but you not adding any elements to it so all your thread are just waiting on that method, that is why you getting OOM.

I do not know how threads are implemented in Java, but one possible reason comes to mind why the queues and threads are not collected: The threads may be wrappers for system threads using system synchronization primitives, in which case the GC cannot automatically collect a waiting thread, since it cannot tell whether the thread is alive or not, i.e. the GC simply does not know that a thread cannot be woken.
I can't say what's the best way to fix it, since I'd need to know what you are trying to do, but you could look at java.util.concurrent to see if it has classes for doing what you need.

You start the thread, so all those new threads will be running asynchronously while the loop continues to create new ones.
Since your code is locking, the threads are life references in the system and cannot be collected. But even if they were doing some work, the threads are unlikely to be terminating as quickly as they are created (at least in this sample), and therefore the GC cannot collect all memory and will eventually fail with an OutOfMemoryException.
Creating as many threads is neither efficient nor efficient. If it is not a requirement to have all those pending operations run in parallel, you may want to use a thread pool and a queue of runnables to process.

The System.gc call does nothing because there is nothing to collect. When a thread starts it increments the threads reference count, not doing so will mean the thread will terminate indeterminately. When the thread's run method completes, then the thread's reference count is decremented.
while (true) {
// just a simple demo, not useful code.
// 0 0 - the first number is thread reference count, the second is abq ref count
final ArrayBlockingQueue<Integer> abq = new ArrayBlockingQueue<Integer>(2);
// 0 1
final Thread t = new Thread(new Runnable() {
#Override
public void run() {
try {
abq.take();
// 2 2
} catch (final InterruptedException e) {
e.printStackTrace();
}
}
});
// 1 1
t.start();
// 2 2 (because the run calls abq.take)
// after end of loop
// 1 1 - each created object's reference count is decreased
}
Now, there is a potential race condition - what if the main loop terminates and does garbage collection before the thread t has a chance to do any processing, i.e. it is suspended by the OS before the abq.take statement is executed? The run method will try to access the abq object after the GC has released it, which would be bad.
To avoid the race condition, you should pass the object as a parameter to the run method. I'm not sure about Java these days, it's been a while, so I'd suggest passing the object as a constructor parameter to a class derived from Runnable. That way, there's an extra reference to abq made before the run method is called, thus ensuring the object is always valid.

Related

how to safely increment while using threads in java

hi guys i was wondering if i can get a little advice im trying to write a program that can counts how many threads are waiting to process a function, and then once a certain number is achieved it releases all the thread. but my problem is i cant increment properly being that i can the all process the increment code at the same time , thus not incrementing it at all.
protected synchronized boolean isOpen()
{
//this code just calls mymethod intrested where the problem lies
lock.interested();
while(!lock.isReady())
{
}
return true;// this statement releases all my threads
}
public synchronized void interested()
{
count++;// how do i make this increment correctly with threads
System.out.println(count+"-"+ lanes+"-"+ThreadID.get());
if(count==lanes)
{
count =0;
ready =true;
}
}
The problem with your approach is that only one thread can enter the synchronized method at a time and hence, you will never proceed, as all but the first threads are waiting to enter the synchronized method while the first thread is performing a busy-wait loop. You have to use wait which not only solves the waste of CPU cycles of your busy wait but will also free the associated lock of the synchronized code so that the next thread can proceed:
protected synchronized boolean isOpen()
{
lock.interested();
while(!lock.isReady())
{
wait(); // now the next thread can enter isOpen()
}
notify(); // releases the previous thread wait()ing in this method
return true;
}
However, note that this works quite unreliable due to your code being split over multiple different objects. It’s strongly recommend to put the code maintaining the counter and code implementing the waiting for the counter into one object in order to run under the same lock. Your code structure must ensure that interested() can’t be invoked on the lock instance with isOpen not noticing. From the two code fragments you have posted, it’s impossible to deduce whether this is the case.
write a program that can counts how many threads are waiting to
process a function, and then once a certain number is achieved it
releases all the threads
A good solution will be to use CountDownLatch.
From the manual:
A CountDownLatch is initialized with a given count. The await methods
block until the current count reaches zero due to invocations of the
countDown() method, after which all waiting threads are released and
any subsequent invocations of await return immediately. This is a
one-shot phenomenon -- the count cannot be reset. If you need a
version that resets the count, consider using a CyclicBarrier.
You can find a good code example here
You should not use synchronised. Because only one thread will acquire monitor at a time.
You can use CountDownLatch. Just define the no of threads while initialising CountDownLatch.
private CountDownLatch countDownLatch = new CountDownLatch(no_of_threads);
protected boolean isOpen()
{
//this code just calls mymethod intrested where the problem lies
countDownLatch.countDown();
countDownLatch.await();
return true;// this statement releases all my threads
}
All the threads are waiting in countDownLatch.await(). Once the required amount of thread comes(countDownLatch.countDown() is called) it will allow to proceed.

Two threads transferring data in both ways between two LinkedConcurrentQueue results in one empty queue while another "steals" everything

Everyone!
I've wrote a class (InAndOut) that extends Thread. This class receives in the constructor two LinkedConcurrentQueue, entrance and exit, and my run method transfers the objets from entrance to exit.
In my main method, I've instanciate two LinkedConcurrentQueue, myQueue1 and myQueue2, with some values in each. Then, I've instanciate two InAndOut, one receiving myQueue1 (entrance) and myQueue2 (exit) and another receiving myQueue2 (entrance) and myQueue1 (exit). Then, I call the start method of both instances.
The result, after some iterations, is the transference of all objects from a queue to another, in other words, myQueue1 becomes empty and myQueue2 "steals" all the objects. But, if I add a sleep call in each iteration (something like 100 ms), then the behavior is like I've expected (equilibrium between element number in both queues).
Why it's happening and how to fix it? There are some way to do not use this sleep call in my run method? Am I doing something wrong?
Here is my source code:
import java.util.concurrent.ConcurrentLinkedQueue;
class InAndOut extends Thread {
ConcurrentLinkedQueue<String> entrance;
ConcurrentLinkedQueue<String> exit;
String name;
public InAndOut(String name, ConcurrentLinkedQueue<String> entrance, ConcurrentLinkedQueue<String> exit){
this.entrance = entrance;
this.exit = exit;
this.name = name;
}
public void run() {
int it = 0;
while(it < 3000){
String value = entrance.poll();
if(value != null){
exit.offer(value);
System.err.println(this.name + " / entrance: " + entrance.size() + " / exit: " + exit.size());
}
//THIS IS THE SLEEP CALL THAT MAKES THE CODE WORK AS EXPECTED
try{
this.sleep(100);
} catch (Exception ex){
}
it++;
}
}
}
public class Main {
public static void main(String[] args) {
ConcurrentLinkedQueue<String> myQueue1 = new ConcurrentLinkedQueue<String>();
ConcurrentLinkedQueue<String> myQueue2 = new ConcurrentLinkedQueue<String>();
myQueue1.offer("a");
myQueue1.offer("b");
myQueue1.offer("c");
myQueue1.offer("d");
myQueue1.offer("e");
myQueue1.offer("f");
myQueue1.offer("g");
myQueue1.offer("h");
myQueue1.offer("i");
myQueue1.offer("j");
myQueue1.offer("k");
myQueue1.offer("l");
myQueue2.offer("m");
myQueue2.offer("n");
myQueue2.offer("o");
myQueue2.offer("p");
myQueue2.offer("q");
myQueue2.offer("r");
myQueue2.offer("s");
myQueue2.offer("t");
myQueue2.offer("u");
myQueue2.offer("v");
myQueue2.offer("w");
InAndOut es = new InAndOut("First", myQueue1, myQueue2);
InAndOut es2 = new InAndOut("Second", myQueue2, myQueue1);
es.start();
es2.start();
}
}
Thanks in advance!
Even if thread scheduling was deterministic the observed behavior remained plausible. As long as both threads perform the same task they might run balanced though you cannot rely on. But as soon as one queue runs empty the tasks are not balanced anymore. Compare:
Thread one polls from a queue which has items. The poll method will modify the source queue's state to reflect the removal, your code inserts the received item into the other queue, creating an internal list node object and modifying the target queue’s state to reflect the insertion. All modifications are performed in a way visible to other threads.
Thread two polls from an empty queue. The poll method checks a reference and finds null and that’s all. No other action is performed.
I think it should be obvious that one thread has far more to do than the other once one queue went empty. More precisely, one thread can finish its 3000 loop iterations (it could even do 300000) in a time that is not enough for the other to perform even a single iteration.
So once one queue is empty, one thread finishes its loop almost immediately and after that the other thread will transfer all items from one queue to the other and finish afterwards too.
So even with an almost deterministic scheduling behavior the balance would always bear the risk of tilting once one queue happens to get empty.
You can raise the chance for a balanced run by adding far more items to the queue to reduce the likelihood of one queue running empty. You can raise the number of iterations (to far bigger than a million) to avoid a thread exiting immediately when the queue runs empty or increment the counter only if a non-null item has been seen. You can use a CountDownLatch to let both threads wait before entering the loop compensating the thread startup overhead to have them run as synchronous as possible.
However, keep in mind that it still remains non-deterministic and polling loops waste CPU resources. Bot it’s ok to try and learn.
The order of execution with threads is undefined, so anything could happen. However since you do not start both threads simultaneously, you can make some assumptions on what might happen:
es is started first, so given a fast enough CPU, it has already pushed everything from queue1 into queue2 before the start of es2, then goes to sleep on take.
es2 starts and puts 1 element from queue2 back to queue1.
es wakes up at the same time and puts the element back.
Since both threads should "about" work at the same speed, one likely result is that there is only 1 or no element in es and all the remaining one in es2.
jtahlborn is exactly right when he says that multithreading is non-deterministic and as such I would suggest you read more into what your expectations are in this application because it isn't quite clear and it is functioning as I would expect it (based on how it's coded).
With that said, you may be looking for a BlockingQueue and not a ConcurrentLinkedQueue. A blocking queue will suspend the thread if empty and wait for it to have an items in it before continuing. Swap out ConcurrentLinkedQueue with LinkedBlockingQueue.
The difference between the two is that if ConcurrentLinkedQueue doesn't have an item it will return quickly with a null value so it can finish through the 3000 iterations very very quickly.

Why does my thread not wake up? (Java)

I'm loosely following a tutorial on Java NIO to create my first multi-threading, networking Java application. The tutorial is basically about creating an echo-server and a client, but at the moment I'm just trying to get as far as a server receiving messages from the clients and logging them to the console. By searching the tutorial page for "EchoServer" you can see the class that I base most of the relevant code on.
My problem is (at least I think it is) that I can't find a way to initialize the queue of messages to be processed so that it can be used as I want to.
The application is running on two threads: a server thread, which listens for connections and socket data, and a worker thread which processes data received by the server thread. When the server thread has received a message, it calls processData(byte[] data) on the worker, where the data is added to a queue:
1. public void processData(byte[] data) {
2. synchronized(queue) {
3. queue.add(new String(data));
4. queue.notify();
5. }
6. }
In the worker thread's run() method, I have the following code:
7. while (true) {
8. String msg;
9.
10. synchronized (queue) {
11. while (queue.isEmpty()) {
12. try {
13. queue.wait();
14. } catch (InterruptedException e) { }
15. }
16. msg = queue.poll();
17. }
18.
19. System.out.println("Processed message: " + msg);
20. }
I have verified in the debugger that the worker thread gets to line 13, but doesn't proceed to line 16, when the server starts. I take that as a sign of a successful wait. I have also verified that the server thread gets to line 4, and calls notify()on the queue. However, the worker thread doesn't seem to wake up.
In the javadoc for wait(), it is stated that
The current thread must own this object's monitor.
Given my inexperience with threads I am not exactly certain what that means, but I have tried instantiating the queue from the worker thread with no success.
Why does my thread not wake up? How do I wake it up correctly?
Update:
As #Fly suggested, I added some log calls to print out System.identityHashCode(queue) and sure enough the queues were different instances.
This is the entire Worker class:
public class Worker implements Runnable {
Queue<String> queue = new LinkedList<String>();
public void processData(byte[] data) { ... }
#Override
public void run() { ... }
}
The worker is instantiated in the main method and passed to the server as follows:
public static void main(String[] args)
{
Worker w = new Worker();
// Give names to threads for debugging purposes
new Thread(w,"WorkerThread").start();
new Thread(new Server(w), "ServerThread").start();
}
The server saves the Worker instance to a private field and calls processData() on that field. Why do I not get the same queue?
Update 2:
The entire code for the server and worker threads is now available here.
I've placed the code from both files in the same paste, so if you want to compile and run the code yourself, you'll have to split them up again. Also, there's abunch of calls to Log.d(), Log.i(), Log.w() and Log.e() - those are just simple logging routines that construct a log message with some extra information (timestamp and such) and outputs to System.out and System.err.
I'm going to guess that you are getting two different queue objects, because you are creating a whole new Worker instances. You didn't post the code that starts the Worker, but assuming that it also instantiates and starts the Server, then the problem is on the line where you assign this.worker = new Worker(); instead of assigning it to the Worker parameter.
public Server(Worker worker) {
this.clients = new ArrayList<ClientHandle>();
this.worker = new Worker(); // <------THIS SHOULD BE this.worker = worker;
try {
this.start();
} catch (IOException e) {
Log.e("An error occurred when trying to start the server.", e,
this.getClass());
}
}
The thread for the Worker is probably using the worker instance passed to the Server constructor, so the Server needs to assign its own worker reference to that same Worker object.
You might want to use LinkedBlockingQueue instead, it internally handles the multithreading part, and you can focus more on logic. For example :
// a shared instance somewhere in your code
LinkedBlockingQueue<String> queue = new LinkedBlockingQueue<String>();
in one of your thread
public void processData(byte[] data) {
queue.offer(new String(data));
}
and in your other thread
while (running) { // private class member, set to false to exit loop
String msg = queue.poll(500, TimeUnit.MILLISECONDS);
if (msg == null) {
// queue was empty
Thread.yield();
} else {
System.out.println("Processed message: " + msg);
}
}
Note : for the sake of completeness, the methode poll throws in InterruptedException that you may handle as you see fit. In this case, the while could be surrounded by the try...catch so to exit if the thread should have been interrupted.
I'm assuming that queue is an instance of some class that implements the Queue interface, and that (therefore) the poll() method doesn't block.
In this case, you simply need to instantiate a single queue object that can be shared by the two threads. The following will do the trick:
Queue<String> queue = new LinkedList<String>();
The LinkedList class is not thread-safe, but provided that you always access and update the queue instance in a synchronized(queue) block, this will take care of thread-safety.
I think that the rest of the code is correct. You appear to be doing the wait / notify correctly. The worker thread should get and print the message.
If this isn't working, then the first thing to check is whether the two threads are using the same queue object. The second thing to check is whether processData is actually being called. A third possibility is that some other code is adding or removing queue entries, and doing it the wrong way.
notify() calls are lost if there is no thread sleeping when notify() is called. So if you go notify() then another thread does wait() afterwards, then you will deadlock.
You want to use a semaphore instead. Unlike condition variables, release()/increment() calls are not lost on semaphores.
Start the semaphore's count at zero. When you add to the queue increase it. When you take from the queue decrease it. You will not get lost wake-up calls this way.
Update
To clear up some confusion regarding condition variables and semaphores.
There are two differences between condition variables and semaphores.
Condition variables, unlike semaphores, are associated with a lock. You must acquire the lock before you call wait() and notify(). Semaphore do not have this restriction. Also, wait() calls release the lock.
notify() calls are lost on condition variables, meaning, if you call notify() and no thread is sleeping with a call to wait(), then the notify() is lost. This is not the case with semaphores. The ordering of acquire() and release() calls on semaphores does not matter because the semaphore maintains a count. This is why they are sometimes called counting semaphores.
In the javadoc for wait(), it is stated that
The current thread must own this object's monitor.
Given my inexperience with threads I am not exactly certain what that
means, but I have tried instantiating the queue from the worker thread
with no success.
They use really bizarre and confusing terminology. As a general rule of thumb, "object's monitor" in Java speak means "object's lock". Every object in Java has, inside it, a lock and one condition variable (wait()/notify()). So what that line means is, before you call wait() or notify() on an object (in you're case the queue object) you much acquire the lock with synchronized(object){} fist. Being "inside" the monitor in Java speak means possessing the lock with synchronized(). The terminology has been adopted from research papers and applied to Java concepts so it is a bit confusing since these words mean something slightly different from what they originally meant.
The code seems to be correct.
Do both threads use the same queue object? You can check this by object id in a debugger.
Does changing notify() to notifyAll() help? There could be another thread that invoked wait() on the queue.
OK, after some more hours of pointlessly looking around the net I decided to just screw around with the code for a while and see what I could get to. This worked:
private static BlockingQueue<String> queue;
private BlockingQueue<String> getQueue() {
if (queue == null) {
queue = new LinkedBlockingQueue<String>();
}
return queue;
}
As Yanick Rochon pointed out the code could be simplified slightly by using a BlockingQueue instead of an ordinary Queue, but the change that made the difference was that I implemented the Singleton pattern.
As this solves my immediate problem to get the app working, I'll call this the answer. Large amounts of kudos should go to #Fly and others for pointing out that the Queue instances might not be the same - without that I would never have figured this out. However, I'm still very curious on why I have to do it this way, so I will ask a new question about that in a moment.

ThreadPoolExecutor's getActiveCount()

I have a ThreadPoolExecutor that seems to be lying to me when I call getActiveCount(). I haven't done a lot of multithreaded programming however, so perhaps I'm doing something incorrectly.
Here's my TPE
#Override
public void afterPropertiesSet() throws Exception {
BlockingQueue<Runnable> workQueue;
int maxQueueLength = threadPoolConfiguration.getMaximumQueueLength();
if (maxQueueLength == 0) {
workQueue = new LinkedBlockingQueue<Runnable>();
} else {
workQueue = new LinkedBlockingQueue<Runnable>(maxQueueLength);
}
pool = new ThreadPoolExecutor(
threadPoolConfiguration.getCorePoolSize(),
threadPoolConfiguration.getMaximumPoolSize(),
threadPoolConfiguration.getKeepAliveTime(),
TimeUnit.valueOf(threadPoolConfiguration.getTimeUnit()),
workQueue,
// Default thread factory creates normal-priority,
// non-daemon threads.
Executors.defaultThreadFactory(),
// Run any rejected task directly in the calling thread.
// In this way no records will be lost due to rejection
// however, no records will be added to the workQueue
// while the calling thread is processing a Task, so set
// your queue-size appropriately.
//
// This also means MaxThreadCount+1 tasks may run
// concurrently. If you REALLY want a max of MaxThreadCount
// threads don't use this.
new ThreadPoolExecutor.CallerRunsPolicy());
}
In this class I also have a DAO that I pass into my Runnable (FooWorker), like so:
#Override
public void addTask(FooRecord record) {
if (pool == null) {
throw new FooException(ERROR_THREAD_POOL_CONFIGURATION_NOT_SET);
}
pool.execute(new FooWorker(context, calculator, dao, record));
}
FooWorker runs record (the only non-singleton) through a state machine via calculator then sends the transitions to the database via dao, like so:
public void run() {
calculator.calculate(record);
dao.save(record);
}
Once my main thread is done creating new tasks I try and wait to make sure all threads finished successfully:
while (pool.getActiveCount() > 0) {
recordHandler.awaitTermination(terminationTimeout,
terminationTimeoutUnit);
}
What I'm seeing from output logs (which are presumably unreliable due to the threading) is that getActiveCount() is returning zero too early, and the while() loop is exiting while my last threads are still printing output from calculator.
Note I've also tried calling pool.shutdown() then using awaitTermination but then the next time my job runs the pool is still shut down.
My only guess is that inside a thread, when I send data into the dao (since it's a singleton created by Spring in the main thread...), java is considering the thread inactive since (I assume) it's processing in/waiting on the main thread.
Intuitively, based only on what I'm seeing, that's my guess. But... Is that really what's happening? Is there a way to "do it right" without putting a manual incremented variable at the top of run() and a decremented at the end to track the number of threads?
If the answer is "don't pass in the dao", then wouldn't I have to "new" a DAO for every thread? My process is already a (beautiful, efficient) beast, but that would really suck.
As the JavaDoc of getActiveCount states, it's an approximate value: you should not base any major business logic decisions on this.
If you want to wait for all scheduled tasks to complete, then you should simply use
pool.shutdown();
pool.awaitTermination(terminationTimeout, terminationTimeoutUnit);
If you need to wait for a specific task to finish, you should use submit() instead of execute() and then check the Future object for completion (either using isDone() if you want to do it non-blocking or by simply calling get() which blocks until the task is done).
The documentation suggests that the method getActiveCount() on ThreadPoolExecutor is not an exact number:
getActiveCount
public int getActiveCount()
Returns the approximate number of threads that are actively executing tasks.
Returns: the number of threads
Personally, when I am doing multithreaded work such as this, I use a variable that I increment as I add tasks, and decrement as I grab their output.

Do I need to use volatile, if 2 different write and read thread will never alive at the same time

By referring to http://www.javamex.com/tutorials/synchronization_volatile.shtml, I am not sure whether I need to use volatile keyword in the following case, due to additional rule 3.
A primitive static variable will be write by Thread A.
The same primitive static variable will be read by Thread B.
Thread B will only run, after Thread A is "dead". ("dead" means, the last statement of Thread A's void run is finished)
Will the new value written by Thread A, will always committed to main memory, after it "dead"? If yes, does it mean I need not volatile keyword if the above 3 conditions are meet?
I am doubt that volatile is being required in this case. As it is required, then ArrayList may broken. As one thread may perform insert and update size member variable. Later, another thread (not-concurrently) may read the ArrayList's size. If you look at ArrayList source code, size is not being declared as volatile.
In JavaDoc of ArrayList, then only mention that ArrayList is not safe to be used for multiple threads access an ArrayList instance concurrently, but not for multiple threads access an ArrayList instance at different timing.
Let me use the following code to issulate this problem
public static void main(String[] args) throws InterruptedException {
// Create and start the thread
final ArrayList<String> list = new ArrayList<String>();
Thread writeThread = new Thread(new Runnable() {
public void run() {
list.add("hello");
}
});
writeThread.join();
Thread readThread = new Thread(new Runnable() {
public void run() {
// Does it guarantee that list.size will always return 1, as this list
// is manipulated by different thread?
// Take note that, within implementation of ArrayList, member
// variable size is not marked as volatile.
assert(1 == list.size());
}
});
readThread.join();
}
Yes, you still need to use volatile (or some other form of synchronization).
The reason why is that the two threads could run on different processors and even if one thread has long finished before the other starts there is no guarantee that the second thread will get the freshest value when it makes the read. If the field is not marked as volatile and no other synchronization is used, then the second thread could get a value that was cached locally on the processor it is running on. That cached value could in theory be out-of-date for a long period of time, including after the first thread completed.
If you use volatile the value will always be written to and read from main memory, bypassing the processor's cached value.
No, you may not need it. despite Mark Byers answer begin fairly accurate, it is limited. synchronized and volatile are not the only ways to correctly pass data between threads. there are other, less talked about "synchronization points". specifically, thread start and thread end are synchronization points. however, the thread which is starting Thread B must have recognized that Thread A is finished (e.g. by joining the thread or checking the thread's state). if this is the case, the the variable does not need to be volatile.
Possibly yes, unless you manually create a memory barrier. If A sets the variable, and B decides to take oit from some registry, you have a problem. So, you need a mmemory barrier, either implicit (lock, volatile) or explicit.
http://java.sun.com/docs/books/jls/third_edition/html/memory.html#17.4.4
The final action in a thread T1
synchronizes-with any action in
another thread T2 that detects that T1
has terminated. T2 may accomplish this
by calling T1.isAlive() or T1.join().
So it is possible to achieve your goal without using volatile.
In many cases, when there are apparent time dependencies, synchronization is being done by someone under the hood, and application doesn't need extra synchronization. Unfortunately this is not the rule, programmers must analyze each case carefully.
One example is Swing worker thread. People would do some calculation in a worker thread, save the result to a variable, then raise an event. The event thread will then read the result of the calculation from the variable. No explicit synchronization is needed from application code, because "raising an event" already did synchronization, so writes from worker thread is visible from event thread.
On one hand, this is a bliss. On the other hand, many people didn't understand this, they omit the synchronization simply because they never thought about the issue. Their programs happen to be correct... this time.
If Thread A definitely dies before Thread B starts reading then it would be possible to avoid using volatile
eg.
public class MyClass {
volatile int x = 0;
public static void main(String[] args) {
final int i = x;
new Thread() {
int j = i;
public void run() {
j = 10;
final int k = j;
new Thread() {
public void run() {
MyClass.x = k;
}
}.start();
}
}.start();
}
}
However, the problem is that whichever Thread starts Thread B will need to now that the value that Thread A is writing to has changed and to not use its own cached version. The easiest way to do this is to get Thread A to spawn Thread B. But if Thread A has nothing else to do when it spawns Thread B then this seems a little pointless (why not just use the same thread).
The other alternative is that if no other thread is dependent on this variable then maybe Thread A could initial a local variable with the volatile variable, do what it needs to do, and then finally write the contents of its local variable back to the volatile variable. Then when Thread B starts it initialises its local variable from the volatile variable and reads only from its local variable thereafter. This should massively reduce the amount of time spent keeping the volatile variable in sync. If this solution seems unacceptable (because of other threads writing to the volatile variable or whatever) then you definitely need to declare the variable volatile.

Categories