ThreadPoolExecutor backport

P

Philipp

Hello
I'm using the backport to java 1.4 of Doug Lea's java.util.concurrent
package. In the doc for ThreadPoolExecutor, there is a snipped of code
to build a pausable thread pool executor. The snipped is below.
Q: Why does the boolean flag isPaused need not be volatile?
As I see it, it will be polled and set by different threads and
nothing guarantees a memory barrier.
Q2: Does it make a difference if you are in the 1.4 or java 5 memory
model?
Thanks for your comments. Phil

--- Code from JavaDoc ---

class PausableThreadPoolExecutor extends ThreadPoolExecutor {
private boolean isPaused;
private ReentrantLock pauseLock = new ReentrantLock();
private Condition unpaused = pauseLock.newCondition();

public PausableThreadPoolExecutor(...) { super(...);

protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
pauseLock.lock();
try {
while (isPaused) unpaused.await();
} catch (InterruptedException ie) {
t.interrupt();
} finally {
pauseLock.unlock();
}
}

public void pause() {
pauseLock.lock();
try {
isPaused = true;
} finally {
pauseLock.unlock();
}
}

public void resume() {
pauseLock.lock();
try {
isPaused = false;
unpaused.signalAll();
} finally {
pauseLock.unlock();
}
}
}}
 
P

Philipp

Lew a écrit :
Philipp wrote:


class PausableThreadPoolExecutor extends ThreadPoolExecutor {
private boolean isPaused;
private ReentrantLock pauseLock = new ReentrantLock();
private Condition unpaused = pauseLock.newCondition();

public PausableThreadPoolExecutor(...) { super(...);

protected void beforeExecute(Thread t, Runnable r) {
super.beforeExecute(t, r);
pauseLock.lock();
try {
while (isPaused) unpaused.await();
} catch (InterruptedException ie) {
t.interrupt();
} finally {
pauseLock.unlock();
}
}

public void pause() {
pauseLock.lock();
try {
isPaused = true;
} finally {
pauseLock.unlock();
}
}

public void resume() {
pauseLock.lock();
try {
isPaused = false;
unpaused.signalAll();
} finally {
pauseLock.unlock();
}
}
}}
Nothing but the 'pauseLock.lock()', that is.

Thanks for your non-answer. It made me look harder.
Actually, the thing that happens is that in beforeExecute(),
unpaused.await() unlocks the acquired lock pauseLock. This then
(later) gets locked by resume() where signalAll awakes the waiting
thread in beforeExecute(). At this time, the waiting thread is awake,
but cannot execute because it must first reacquire the lock (which is
still held in resume() ). As soon as resume() releases the lock, it is
reacquired by beforeExecute(). Now what makes it all work without the
volatile keyword, is that the unlock() in resume() establishes a
happens-before relation with respect to a subsequent lock of
pauseLock. So the value of isPaused is updated as soon as the waiting
thread starts to run again.

Phil
 
L

Lew

Philipp said:
Thanks for your non-answer. It made me look harder.

"non-answer"? It turned to to be exactly the answer, as your
description clearly shows.

Happy to help.
 
R

Robert Klemme

Philipp wrote:

Btw, AFAIK the implementation you are using preceded Java 5 so it is not
a backport.
Q2: Does it make a difference if you are in the 1.4 or java [sic] 5
memory model?

Yes, but not to this snippet.

Are you sure with regard to "volatile"? I faintly remember articles
about the flaws of the Java memory model before Java 5 and I believe
volatile handling was one of them. Or am I mixing up something?

Kind regards

robert
 
L

Lew

Philipp wrote:

Btw, AFAIK the implementation you are using preceded Java 5 so it is not
a backport.
Q2: Does it make a difference if you are in the 1.4 or java [sic] 5
memory model?
Yes, but not to this snippet.

Are you sure with regard to "volatile"?  I faintly remember articles
about the flaws of the Java memory model before Java 5 and I believe
volatile handling was one of them.  Or am I mixing up something?

You are correct, but 'volatile' was not used in the snippet, so that
difference is, as stated, not relevant to the snippet.
 
R

Robert Klemme

Philipp wrote:
Btw, AFAIK the implementation you are using preceded Java 5 so it is not
a backport.
Q2: Does it make a difference if you are in the 1.4 or java [sic] 5
memory model?
Yes, but not to this snippet.
Are you sure with regard to "volatile"? I faintly remember articles
about the flaws of the Java memory model before Java 5 and I believe
volatile handling was one of them. Or am I mixing up something?

You are correct, but 'volatile' was not used in the snippet, so that
difference is, as stated, not relevant to the snippet.

Actually I canceled my posting because I discovered my reading error the
second after hitting "send" - but apparently Usenet was too fast for me. :)

Thanks for clarifying anyway! Always good to get some of your well
thought out advice / comments.

Kind regards

robert
 
L

Lew

What you are remembering is that 'volatile' prior to Java 5 only
guaranteed visibility of changes through the volatile variable
itself. Other changes might not have propagated.

So given

class Foo
{
volatile int flag;
int value; // not volatile
...
}

the old memory model would guarantee visbility of changes to 'flag',
but not other changes. Code like:

value += 17;
flag = 1;

in one thread guaranteed that another thread would see 'flag' as 1,
but not that it would see the change in 'value'. In the new memory
model, the change to 'value' /happens-before/ the change to 'flag', so
it is visible across threads.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,773
Messages
2,569,594
Members
45,125
Latest member
VinayKumar Nevatia_
Top