Working with threads. Example from java docs

P

Progzmaster

Hello there I am learing java like everybody here and I ecounter a small
problem that I am unable to solve.
This is the link to Java lang. spec. "volatile fields"
http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.3.1.4

There is a paragraph:
--------------------------------------------------------------------------------------------------------------------
If, in the following example, one thread repeatedly calls the method one
(but no more than Integer.MAX_VALUE times in all), and another thread
repeatedly calls the method two:
class Test {
static int i = 0, j = 0;
static void one() { i++; j++; }
static void two() {
System.out.println("i=" + i + " j=" + j);
}
}then method two could occasionally print a value for j that is greater than
the value of i,
because the example includes no synchronization and, under the rules
explained in §17,
the shared values of i and j might be updated out of order.
-----------------------------------------------------------------------------------------------------------------------

I tryied to write a simple program that is based on the above example so
that I can see different values of i and j.
I wrote one but unfortunatelly every time program runs each line shows the
same values for i and j.
Can you help me and fix my code or write another similar program that will
be doing such a thing
so I can belive that it could happen - ( method two could occasionally
print a value for j that is greater than the value of i )

This is my code:
---------------------------------------------------------------------------------------------------
class Test
{
static int i=0, j=0;
public static void one() { i++; j++; }
public static void two()
{
System.out.println( "i=" + i + " j=" + j );
}
}

class T1 extends java.lang.Thread
{
public T1()
{
super();
start();
}

public void run( )
{
while( true )
{
Test.one();
if ( this.interrupted() ) return;
yield();
}
}
}

class T2 extends java.lang.Thread
{
public T2()
{
super();
start();
}

public void run( )
{
while( true )
{
Test.two();
if ( this.interrupted() ) return;
yield();
}
}
}

public class Ex01
{
public static void main( java.lang.String [] args )
throws java.lang.InterruptedException
{
T2 t2 = new T2( );
T1 t1 = new T1( );
Thread.sleep(2000);
t1.interrupt();
t2.interrupt();
}
}
 
D

danharrisandrews

Hi Progzmaster,

Try this:

public static void one() {
i++;
Thread.yield();
j++;
}

Also this line "if ( this.interrupted() )" would b better if written
like this "if ( Thread.interrupted() )" since interrupted is a static
method.


Cheers,

Dan Andrews

- - - - - - - - - - - - - - - - - - - - - - - -
Ansir Development Limited www.ansir.ca
- - - - - - - - - - - - - - - - - - - - - - - -

Hello there I am learing java like everybody here and I ecounter a small
problem that I am unable to solve.
This is the link to Java lang. spec. "volatile fields"
http://java.sun.com/docs/books/jls/third_edition/html/classes.html#8.3.1.4

There is a paragraph:
--------------------------------------------------------------------------------------------------------------------
If, in the following example, one thread repeatedly calls the method one
(but no more than Integer.MAX_VALUE times in all), and another thread
repeatedly calls the method two:
class Test {
static int i = 0, j = 0;
static void one() { i++; j++; }
static void two() {
System.out.println("i=" + i + " j=" + j);
}
}then method two could occasionally print a value for j that is greater than
the value of i,
because the example includes no synchronization and, under the rules
explained in §17,
the shared values of i and j might be updated out of order.
-----------------------------------------------------------------------------------------------------------------------

I tryied to write a simple program that is based on the above example so
that I can see different values of i and j.
I wrote one but unfortunatelly every time program runs each line shows the
same values for i and j.
Can you help me and fix my code or write another similar program that will
be doing such a thing
so I can belive that it could happen - ( method two could occasionally
print a value for j that is greater than the value of i )

This is my code:
---------------------------------------------------------------------------------------------------
class Test
{
static int i=0, j=0;
public static void one() { i++; j++; }
public static void two()
{
System.out.println( "i=" + i + " j=" + j );
}
}

class T1 extends java.lang.Thread
{
public T1()
{
super();
start();
}

public void run( )
{
while( true )
{
Test.one();
if ( this.interrupted() ) return;
yield();
}
}
}

class T2 extends java.lang.Thread
{
public T2()
{
super();
start();
}

public void run( )
{
while( true )
{
Test.two();
if ( this.interrupted() ) return;
yield();
}
}
}

public class Ex01
{
public static void main( java.lang.String [] args )
throws java.lang.InterruptedException
{
T2 t2 = new T2( );
T1 t1 = new T1( );
Thread.sleep(2000);
t1.interrupt();
t2.interrupt();
}
}
 
S

Soren Kuula

Progzmaster said:
There is a paragraph:
--------------------------------------------------------------------------------------------------------------------
If, in the following example, one thread repeatedly calls the method one
(but no more than Integer.MAX_VALUE times in all), and another thread
repeatedly calls the method two:
class Test {
static int i = 0, j = 0;
static void one() { i++; j++; }
static void two() {
System.out.println("i=" + i + " j=" + j);
}

I think that what they try to say (saying that it might happen that j>i
at some time, for some thread) is: There is no guarantee that the
compiler generates code that update fields in the same order as the
update operations are written:
-- OK if there is an update and then a read, then the order of the two
is preserved.
-- If you use the volatile keyword, then such a guarantee WILL be made.
-- If you use the synchronized keyword, there is no guarantee. On the
other hand, no other thread is allowed to break in between updates (and
get surprised), so any effect is completely hidden.

In your case, a compiler is free to translate one() to something like:

1) Push i on stack
2) Run a pop-off-stack-add-one-and-push-back-on-stack JVM instruction (I
think there even is such an instruction!)
3) Push j on stack
4) Run a pop-off-stack-add-one-and-push-back-on-stack JVM instruction
5) pop-off-stack, store into j location
6) pop-off-stack, store into i location

It will work fine, but see how j is written back before i in step 5-6??
If the other thread takes over between steps 5 and 6, it will see j>i.

I guess you can reproduce only if your compiler does it this way. It
might also do the steps in the order 1-2-6-3-4-5.

Soren
 
P

Progzmaster

One more time thank you for your help ,
I can't understand why it didn't happen in first version, increments
aren't atomic operations after all.
The CPU time scheduler is really a big question mark :) You can never
preddict the operation sequence

Uzytkownik <[email protected]> napisal w wiadomosci
Hi Progzmaster,

Try this:

public static void one() {
i++;
Thread.yield();
j++;
}

Also this line "if ( this.interrupted() )" would b better if written
like this "if ( Thread.interrupted() )" since interrupted is a static
method.


Cheers,

Dan Andrews

- - - - - - - - - - - - - - - - - - - - - - - -
Ansir Development Limited www.ansir.ca
- - - - - - - - - - - - - - - - - - - - - - - -
 
D

danharrisandrews

Soren,

Right you are (j>i). I miss read the original question.

The finer point that I over looked is that a thread can have local
copies of variables and that data may be different that the local copy
in another thread or that of main memory. The volatile modifier
effectively prohibits the thread from having a local copy of a variable
that is different from main memory, so if the variable is modified by a
thread it must also be touched in main memory too.

Cheers,

Dan Andrews

- - - - - - - - - - - - - - - - - - - - - - - -
Ansir Development Limited www.ansir.ca
- - - - - - - - - - - - - - - - - - - - - - - -

Soren said:
I think that what they try to say (saying that it might happen that j>i

[snip]
 
P

Patricia Shanahan

Progzmaster said:
One more time thank you for your help ,
I can't understand why it didn't happen in first version, increments
aren't atomic operations after all.
The CPU time scheduler is really a big question mark :) You can never
preddict the operation sequence

Correct. However, a lot of scheduler behavior can be explained by
remembering a few basic principles:

1. Context switches waste time, so the scheduler tries to do them as
infrequently as possible subject to the other objectives. It's a bit
like being in the middle of some paperwork, with all the right papers
spread out on your desk, and having to switch to a different job that
needs different papers.

2. On the other hand, the scheduler tries to be fair in the long term
among jobs of similar priority.

3. Thread.yield() requires a pause in the current thread to allow other
threads to run, even if the dispatcher is not yet ready to take the
processor away from it.

Now look at the original program in terms of these ideas. The yield
calls cause switches between the two threads. The time from one yield to
the next is so short that the dispatcher is very unlikely to switch
between the two threads except at the yields.

I was able to get some inconsistent outputs from your original program
by running it on a dual processor system, where both threads can really
run at the same time, rather than time sharing a single processor.

Patricia
 

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

Forum statistics

Threads
473,770
Messages
2,569,584
Members
45,075
Latest member
MakersCBDBloodSupport

Latest Threads

Top