Cannot force a simple 'race condition' when extending Thread, only when using ExecutorService

StackOverflow https://stackoverflow.com/questions/21737549

Domanda

I am working through Bruce Eckel's Thinking in Java 4th edition.

In the chapter on concurrency there is an exercise on race conditions, when they might occur and how to prevent them.

Unfortunately I cannot seem to replicate the race condition when extending a simple Thread, but using the same code in a Runnable and an ExecutorService I do get the race condition.

Can anyone explain the difference?

My basic class which must always be even:

class EvenNumber {
    private int value=2;

    public int getValue(){
        return value;
    }
    public boolean validate(){
        if (value%2 !=0) {
            System.err.println(value + " is not an even number!");
            throw new RuntimeException();
        }
        return true;
    }


    protected void addTwo(){
            ++value;
            Thread.yield(); //problem should occur here
            ++value;
    }

    //public mutator
    public void addLotsOfTwos(int n){
        for(int i=0;i<n;i++){
            addTwo();
        }
    }
}

Extending a thread I can't seem to be able to get a race condition going.

class EvenCheckerThread extends Thread {

    private static int counter =0;
    private final int id;
    private  EvenNumber even;

    EvenCheckerThread(EvenNumber even){
        this.id = ++counter;
        this.even = even;
    }

    public void run(){
        System.out.println("Start thread#" + id + "using " + even);

        for(int i=0; i<10 ;i++){
            even.addLotsOfTwos(10);
            even.validate();
        }

        System.out.println("Finish thread#" + id);
    }
}

Exactly same code in a Runnable quickly throws an exception:

class EvenCheckerRunnable implements Runnable {

    private static int counter =0;
    private final int id;
    private  EvenNumber even;

    EvenCheckerRunnable(EvenNumber even){
        this.id = ++counter;
        this.even = even;

    }

    public void run(){
        System.out.println("Start thread#" + id + "using " + even);

        for(int i=0; i<10 ;i++){
            even.addLotsOfTwos(10);
            even.validate();
        }

        System.out.println("Finish thread#" + id);
    }
}

I try and test my classes from E11.main(). However, passing the same EvenNumber object to the Thread doesn't give me an exception even though I've created 100 threads, they all seem to start and finish nicely in order.

Creating 10 threads using Executors quickly throws an exception.

public class E11 {

    public static void main(String[] args) {
        EvenNumber even = new EvenNumber();

        for(int i=0;i<100;i++){
            new EvenCheckerThread(even).run();
        }


        /*ExecutorService exec = Executors.newCachedThreadPool();

        for(int i=0;i<10;i++){
            exec.execute(new EvenCheckerRunnable(even));
        }*/
    }
}

I'm sure I've misunderstood something at a very basic level, but I don't know what...

È stato utile?

Soluzione

This piece of code:

for(int i=0;i<100;i++){
    new EvenCheckerThread(even).run();
}

does not run the code in new Thread, so everything gets properly executed in one single sequence. You created an instance of the class Thread, but the run() method simply executes on the current Thread. Instead, try to call the start() method to actually start a new Thread.:

for(int i=0;i<100;i++){
    new EvenCheckerThread(even).start();
}
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top