Question porting CPiJ Examples to java.util.concurrent

classic Classic list List threaded Threaded
3 messages Options
Reply | Threaded
Open this post in threaded view
|

Question porting CPiJ Examples to java.util.concurrent

robertkuhar
I am a member of a user group presently studying "Concurrent Programming in
Java Second Edition" using the Nik Boyd study guide.  This is a great book for
concepts, but the examples are all coded to the
EDU.oswego.cs.dl.util.concurrent library not the JDK1.5 java.util.concurrent.
As an exercise each session, we typically port the examples from the book up to
java.util.concurrent.  There are mismatches that are confusing us.  

In particular, we often stumble around the mismatch between
EDU.oswego.cs.dl.util.concurrent.Sync and java.util.concurrent.lock.Lock.  The
methods that cause the most pain are the one's that don't throws
InterruptedException: try() and lock().  What are we supposed to do when
implementing lock() or tryLock() with InterruptedExceptions that come out of
wait()?  Do we just swallow them and go back to waiting?

Attached is the full source from the Semaphore example in 3.7.1 Acquire-Release
Protocols.  Note the waitForAPermit() method exists only to avoid a bunch of
duplicate code.  Here is an excerpt showing our lock() and lockInterruptibly()
implementations:

public void lock() {
  synchronized (this) {
    while (true) {
      try {
        waitForAPermit();
        return;
      } catch (InterruptedException ie) {
        // swallow it.
        // TODO: Do I have obligation to reraise Thread.interrupt()?
        // TODO: InterruptedException to become some RuntimeException here.
That's not how lock() is supposed to behave, is it?
      }
    } // end while()
  } // end synchronized(this)
}

public void lockInterruptibly() throws InterruptedException {
  synchronized (this) {
    waitForAPermit();
  } // end synchronized(this)
}

private void waitForAPermit() throws InterruptedException {
  try {
    while (this.permits < 0) {
      wait();
    } // end while()
    this.permits--;
  } catch (InterruptedException ie) {
    notify();
    throw ie;
  }
}

Are we doing the correct thing here "swallowing" InterruptedExceptions in our
non interruptable implemenations of lock() and tryLock() (or did the group
collectively forget something we learned earlier in the book)?

One of our members always wants to throw some RuntimeException in the
implementations that "swallow" the InterruptedExceptions.  That's not right, is
it?  And, if so, why or why not?

When we "swallow" an InterruptedException do we have an obligation to reraise
the interrupt()?  That would just have the affect of coming back up to us as an
InterruptedException, no?

Any light you could shed is greatly appreciated.

Bob

__________________________________________________
Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam protection around
http://mail.yahoo.com 
_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://altair.cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Question porting CPiJ Examples to java.util.concurrent

robertkuhar
I hate when I do that.  This time I'll actually attach the source.

--- Robert Kuhar <[hidden email]> wrote:

> I am a member of a user group presently studying "Concurrent Programming in
> Java Second Edition" using the Nik Boyd study guide.  This is a great book
> for
> concepts, but the examples are all coded to the
> EDU.oswego.cs.dl.util.concurrent library not the JDK1.5 java.util.concurrent.
>
> As an exercise each session, we typically port the examples from the book up
> to
> java.util.concurrent.  There are mismatches that are confusing us.  
>
> In particular, we often stumble around the mismatch between
> EDU.oswego.cs.dl.util.concurrent.Sync and java.util.concurrent.lock.Lock.
> The
> methods that cause the most pain are the one's that don't throws
> InterruptedException: try() and lock().  What are we supposed to do when
> implementing lock() or tryLock() with InterruptedExceptions that come out of
> wait()?  Do we just swallow them and go back to waiting?
>
> Attached is the full source from the Semaphore example in 3.7.1
> Acquire-Release
> Protocols.  Note the waitForAPermit() method exists only to avoid a bunch of
> duplicate code.  Here is an excerpt showing our lock() and
> lockInterruptibly()
> implementations:
>
> public void lock() {
>   synchronized (this) {
>     while (true) {
>       try {
>         waitForAPermit();
>         return;
>       } catch (InterruptedException ie) {
>         // swallow it.
>         // TODO: Do I have obligation to reraise Thread.interrupt()?
>         // TODO: InterruptedException to become some RuntimeException here.
> That's not how lock() is supposed to behave, is it?
>       }
>     } // end while()
>   } // end synchronized(this)
> }
>
> public void lockInterruptibly() throws InterruptedException {
>   synchronized (this) {
>     waitForAPermit();
>   } // end synchronized(this)
> }
>
> private void waitForAPermit() throws InterruptedException {
>   try {
>     while (this.permits < 0) {
>       wait();
>     } // end while()
>     this.permits--;
>   } catch (InterruptedException ie) {
>     notify();
>     throw ie;
>   }
> }
>
> Are we doing the correct thing here "swallowing" InterruptedExceptions in our
> non interruptable implemenations of lock() and tryLock() (or did the group
> collectively forget something we learned earlier in the book)?
>
> One of our members always wants to throw some RuntimeException in the
> implementations that "swallow" the InterruptedExceptions.  That's not right,
> is
> it?  And, if so, why or why not?
>
> When we "swallow" an InterruptedException do we have an obligation to reraise
> the interrupt()?  That would just have the affect of coming back up to us as
> an
> InterruptedException, no?
>
> Any light you could shed is greatly appreciated.
>
> Bob
>
> __________________________________________________
> Do You Yahoo!?
> Tired of spam?  Yahoo! Mail has the best spam protection around
> http://mail.yahoo.com 
>
__________________________________________________
Do You Yahoo!?
Tired of spam?  Yahoo! Mail has the best spam protection around
http://mail.yahoo.com 
package ch03_7_1;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

public class CPiJSemaphore implements Lock {
    private long permits;

    public CPiJSemaphore(long permits) {
        this.permits = permits;
    }

    public void lock() {
        synchronized (this) {
            while (true) {
                try {
                    waitForAPermit();
                    return;
                } catch (InterruptedException ie) {
                    // swallow it.
                    // TODO: Do I have obligation to reraise Thread.interrupt()?
                    // TODO: Steve wants InterruptedException to become some RuntimeException here.
                }
            } // end while()
        } // end synchronized(this)
    }

    public void lockInterruptibly() throws InterruptedException {
        synchronized (this) {
            waitForAPermit();
        } // end synchronized(this)
    }

    private void waitForAPermit()
        throws InterruptedException {
        try {
            while (this.permits < 0) {
                wait();
            } // end while()
            this.permits--;
        } catch (InterruptedException ie) {
            notify();
            throw ie;
        }
    }

    public boolean tryLock() {
        try {
            return tryLock(0l, TimeUnit.MILLISECONDS);
        } catch(InterruptedException ie) {
            // swallow it.
        }
        return false;
    }

    public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
        if (Thread.interrupted()) {
            throw new InterruptedException();
        }
        synchronized (this) {
            if (this.permits > 0) {
                this.permits--;
                return true;
            } else if (time <= 0) {
                // Quick out on "don't wait"...
                return false;
            } else {
                try {
                    long startWaitTime = System.currentTimeMillis();
                    long waitTime = unit.toMillis(time);
                    while (true) {
                        wait(waitTime);
                        if (this.permits > 0) {
                            this.permits--;
                            return true;
                        } else {
                            long now = System.currentTimeMillis();
                            waitTime = unit.toMillis(time) - (now - startWaitTime);
                            if (waitTime <= 0) {
                                return false;
                            }
                        }
                    } // end while()
                } catch (InterruptedException ie) {
                    notify();
                    throw ie;
                }
            }
        } // end synchronized(this)
    }

    public void unlock() {
        this.permits++;
        notify();
    }

    public Condition newCondition() {
        throw new UnsupportedOperationException();
    }

}

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://altair.cs.oswego.edu/mailman/listinfo/concurrency-interest
Reply | Threaded
Open this post in threaded view
|

Re: Question porting CPiJ Examples tojava.util.concurrent

Dawid Kurzyniec
In reply to this post by robertkuhar
Robert Kuhar wrote:

>I am a member of a user group presently studying "Concurrent Programming in
>Java Second Edition" using the Nik Boyd study guide.  This is a great book for
>concepts, but the examples are all coded to the
>EDU.oswego.cs.dl.util.concurrent library not the JDK1.5 java.util.concurrent.
>As an exercise each session, we typically port the examples from the book up to
>java.util.concurrent.  There are mismatches that are confusing us.  
>
>In particular, we often stumble around the mismatch between
>EDU.oswego.cs.dl.util.concurrent.Sync and java.util.concurrent.lock.Lock.  The
>methods that cause the most pain are the one's that don't throws
>InterruptedException: try() and lock().  What are we supposed to do when
>implementing lock() or tryLock() with InterruptedExceptions that come out of
>wait()?  Do we just swallow them and go back to waiting?
>
>Attached is the full source from the Semaphore example in 3.7.1 Acquire-Release
>Protocols.  Note the waitForAPermit() method exists only to avoid a bunch of
>duplicate code.  Here is an excerpt showing our lock() and lockInterruptibly()
>implementations:
>
>(...)
>
>Are we doing the correct thing here "swallowing" InterruptedExceptions in our
>non interruptable implemenations of lock() and tryLock() (or did the group
>collectively forget something we learned earlier in the book)?
>  
>
Yes and no. You should re-raise the interrupt afterwards (see below).

>One of our members always wants to throw some RuntimeException in the
>implementations that "swallow" the InterruptedExceptions.  That's not right, is
>it?  And, if so, why or why not?
>  
>
I think not; the spec says that unchecked exceptions can be thrown upon
a detection of erroneous use of a lock. Arguably, interruption does not
qualify as such.

>When we "swallow" an InterruptedException do we have an obligation to reraise
>the interrupt()?  That would just have the affect of coming back up to us as an
>InterruptedException, no?
>
>  
>

You should re-raise the interrupt when you are exiting from the method.
It may come back as an InterruptedException but later (on another
blocking operation); it won't affect the lock(). This is how it's done
in backport-util-concurrent (ReentrantLock):

       

        public void lock() {
            Thread caller = Thread.currentThread();
            synchronized (this) {
                if (owner_ == null) {
                    owner_ = caller;
                    holds_ = 1;
                    return;
                }
                else if (caller == owner_) {
                    incHolds();
                    return;
                }
                else {
                    boolean wasInterrupted = Thread.interrupted();
                    try {
                        do {
                            try {
                                wait();
                            }
                            catch (InterruptedException e) {
                                wasInterrupted = true;
                                // no need to notify; if we were signalled, we
                                // will act as signalled, ignoring the
                                // interruption
                            }
                        }
                        while (owner_ != null);

                        owner_ = caller;
                        holds_ = 1;
                        return;
                    }
                    finally {
                        if (wasInterrupted) Thread.currentThread().interrupt();
                    }
                }
            }
        }


Kind regards,
Dawid Kurzyniec

_______________________________________________
Concurrency-interest mailing list
[hidden email]
http://altair.cs.oswego.edu/mailman/listinfo/concurrency-interest