开发者

Java 6 Threading output is not Asynchronous?

This code should produce even and uneven output because there is no synchronized on any methods. Yet the output on my JVM is always even. I am really confused as this example comes straight out of Doug Lea.

public class TestMethod implements Runnable {

private int index = 0;

    public void testThisMethod() {
        index++;
        index++;
        System.out.println(Thread.currentThread().toString() + " "
                    + index );

    }

    public void run() {
        while(true) {
            this.testThisMethod();
        }
    }

    public static void main(String args[]) {
        int i = 0;
        TestMethod method = new TestMethod();
        while(i < 20) {
            new Thread(method).start();
            i++;
        }
    }
}

Output

Thread[Thread-8,5,main] 135134

Thread[Thread-8,5,main] 135136

开发者_开发知识库

Thread[Thread-8,5,main] 135138

Thread[Thread-8,5,main] 135140

Thread[Thread-8,5,main] 135142

Thread[Thread-8,5,main] 135144


I tried with volatile and got the following (with an if to print only if odd):

Thread[Thread-12,5,main] 122229779
Thread[Thread-12,5,main] 122229781
Thread[Thread-12,5,main] 122229783
Thread[Thread-12,5,main] 122229785
Thread[Thread-12,5,main] 122229787

Answer to comments:

the index is infact shared, because we have one TestMethod instance but many Threads that call testThisMethod() on the one TestMethod that we have.


Code (no changes besides the mentioned above):

public class TestMethod implements Runnable {

    volatile private int index = 0;

        public void testThisMethod() {
            index++;
            index++;
            if(index % 2 != 0){
            System.out.println(Thread.currentThread().toString() + " "
                        + index );
            }

        }

        public void run() {
            while(true) {
                this.testThisMethod();
            }
        }

        public static void main(String args[]) {
            int i = 0;
            TestMethod method = new TestMethod();
            while(i < 20) {
                new Thread(method).start();
                i++;
            }
        }
    }


First off all: as others have noted there's no guarantee at all, that your threads do get interrupted between the two increment operations.

Note that printing to System.out pretty likely forces some kind of synchronization on your threads, so your threads are pretty likely to have just started a time slice when they return from that, so they will probably complete the two incrementation operations and then wait for the shared resource for System.out.

Try replacing the System.out.println() with something like this:

int snapshot = index;
if (snapshot % 2 != 0) {
  System.out.println("Oh noes! " + snapshot);
}


You don't know that. The point of automatic scheduling is that it makes no guarantees. It might treat two threads that run the same code completely different. Or completely the same. Or completely the same for an hour and then suddenly different...

The point is, even if you fix the problems mentioned in the other answers, you still cannot rely on things coming out a particular way; you must always be prepared for any possible interleaving that the Java memory and threading model allows, and that includes the possibility that the println always happens after an even number of increments, even if that seems unlikely to you on the face of it.


The result is exactly as I would expect. index is being incremented twice between outputs, and there is no interaction between threads.

To turn the question around - why would you expect odd outputs?

EDIT: Whoops. I wrongly assumed a new runnable was being created per Thread, and therefore there was a distinct index per thread, rather than shared. Disturbing how such a flawed answer got 3 upvotes though...


You have not marked index as volatile. This means that the compiler is allowed to optimize accesses to it, and it probably merges your 2 increments to one addition.


You get the output of the very first thread you start, because this thread loops and gives no chance to other threads to run.

So you should Thread.sleep() or (not recommended) Thread.yield() in the loop.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜