Review request for 8022208: Intermittent test failures in java/lang/Thread/ThreadStateTest.java
Mandy Chung
mandy.chung at oracle.com
Thu Oct 31 20:32:06 PDT 2013
On 10/31/2013 5:38 PM, David Holmes wrote:
> Hi Mandy,
>
> On 1/11/2013 5:11 AM, Mandy Chung wrote:
>> Updated webrev that has a new
>> test/lib/testlibrary/ThreadStateController.java and also change to use
>> AtomicInteger:
>> http://cr.openjdk.java.net/~mchung/jdk8/webrevs/8022208/webrev.01/
>
> Sorry but I don't see how this works - and that applies to the old
> version too! (Which I know I've looked at before so this is somewhat
> unsettling for me :( ).
>
> First I found it confusing to track which thread was which in the
> refactoring (which in itself is a good idea). Inside
> ThreadStateController "myThread" doesn't mean anything - that comes
> from the calling context - I suggest changing to refer to "this
> thread" or "the current thread" as appropriate. eg "Have the current
> thread wait until this thread is about to block" or whatever is needed.
>
I wasn't happy with "myThread" too and should rename it.
> Looking at an actual test we have eg:
>
> myThread.goWaiting();
> ThreadStateController.checkThreadState(myThread, Thread.State.WAITING);
>
> First: why is checkThreadState static rather than just an instance
> method?
>
Yes it can.
> So goWaiting is supposed to tell myThread to go to a "waiting" state
> so that the main thread can then verify that. Lets assume for
> arguments sake that the thread is currently RUNNABLE so it is
> currently looping around in run() doing the little math exercise.
> goWaiting does:
>
> public void goWaiting() {
> System.out.println("Waiting myThread to go waiting.");
> setState(WAITING);
> // wait for MyThread to get to just before wait on object.
> phaser.arriveAndAwaitAdvance();
> }
>
> and setState does:
>
> case WAITING:
> case TIMED_WAITING:
> state = newState;
> synchronized (lock) {
> lock.notify();
> }
> break;
>
>
> so as soon as we update "state" myThread is capable of changing what
> it is doing in run() to:
>
> case WAITING: {
> synchronized (lock) {
> // signal main thread.
> phaser.arrive();
> System.out.println(" myThread is going to wait.");
> try {
> lock.wait();
> } catch (InterruptedException e) {
> // ignore
> interrupted.incrementAndGet();
> }
> }
> break;
>
> so now we have a race between the two threads to see who can grab the
> lock first. If it is the main thread then we issue a notify when
> nothing is waiting and so the subsequent wait() by myThread will
> potentially wait forever. At least in that case the main thread will
> see that it is waiting!
>
> If "myThread" wins the race it will wait after signalling the phaser
> and the main thread will then issue the notify allowing myThread to
> proceed (and do what? process the WAITING case again??). So there is
> no guarantee that myThread will be waiting when the main thread checks
> the state!
>
> Similarly for issuing the unpark in the parking cases.
>
> AFAICS the basic approach here should be:
> - tell myThread to go to state X
> - wait until myThread should be in state X
> - verify myThread is in state X
> - allow myThread to escape from state X
>
> but this code does the last step second.
>
> ???
>
I was looking at the intermittent failures and fix the problem I
identified. What you said above is definitely potential race that I
didn't have analyzed the waiting state thoroughly. It's time to revisit
the whole test and see if there is a better way to code this.
thanks for the review.
Mandy
More information about the serviceability-dev
mailing list