Koray Tugay
Koray Tugay

Reputation: 23790

Why is this Java Program not showing me the result I expect?

Here is the code I have:

/* User: [email protected] Date: 21/02/15 Time: 19:53 */

public class DriverClass {

    public static void main(String[] args) throws InterruptedException {

        int upper = 15;
        Integer sumValue = null;
        Thread thread = new Thread(new Summation(upper, sumValue));
        thread.start();
        thread.join();
        System.out.println(sumValue);

    }

}

and the Summation class:

class Summation implements Runnable {

    private int upper;
    private Integer sumValue;

    public Summation(int upper, Integer sumValue) {
        this.upper = upper;
        this.sumValue = sumValue;
    }

    public void run() {
        System.out.println("Thread started...");
        int sum = 0;
        for (int i = 0; i <= upper; i++) {
            sum += i;
        }
        System.out.println("Sum is:" + sum);
        sumValue = sum;
    }

}

I will see in the console:

Thread started...
Sum is:120
null

Why the last line is 'null' ? I am expecting to see 120 again?

Upvotes: 2

Views: 73

Answers (5)

JB Nizet
JB Nizet

Reputation: 691715

OK. Let me explain with a picture. First you create a reference in the main method and assign null to it:

main
----
sumValue -----> null

Then you pass this reference to the Summation constructor. This creates a copy of the reference:

main
----
sumValue -----> null
                ^
Summation       |
----            |
sumValue --------

Then the Summation.run() emthod assigns a new integer value to the Summation.sumValue reference:

main
----
sumValue -----> null

Summation       
----            
sumValue -----> 120

As you see, the reference in the main method still points to null. That's why null is printed.

What you can do, instead, is pass a reference to a mutable object, whose state can change (like an AtomicInteger for example):

main
----
sumValue -----> AtomicInteger(0)

Then pass it to Summation:

main
----
sumValue -----> AtomicInteger(0)
                ^
Summation       |
----            |
sumValue --------

Then in Summation, modify the state of the AtomicInteger: sumValue.set(120):

main
----
sumValue -----> AtomicInteger(120)
                ^
Summation       |
----            |
sumValue --------

And then, when printing the AtomicInteger in the main method, you'll have 120, because then the main method and the Summation object have two references pointing to the same object.

Or better, you could store the result as an Integer in the Summation object, and ask for the result in the main method once the computation is done:

System.out.println(summation.getSumValue());

Upvotes: 4

antonio
antonio

Reputation: 18242

This happens because Integer is immutable.

You are passing your sumValue to Summation via the constructor, but in the constructor a new Integer is created to copy the value of the one you are passing to it.

To better understand what is happening here you may want to take a look at this article keeping in mind that you are working with an immutable object (your Integer object)

Edit:

Creating your own class extending Integer? take a look at this immutable class should be final?

You can instead create an accessor a getter for your sumValue:

public class DriverClass {

    public static void main(String[] args) throws InterruptedException {
        int upper = 15;
        Integer sumValue = null;
        Summation sum = new Summation(upper, sumValue);

        Thread thread = new Thread(sum);
        thread.start();
        thread.join();

        sumValue = sum.getSumValue();

        System.out.println(sumValue);
    }

}

class Summation implements Runnable {

    private final int upper;
    private Integer sumValue;

    public Summation(int upper, Integer sumValue) {
        this.upper = upper;
        this.sumValue = sumValue;
    }

    @Override
    public void run() {
        System.out.println("Thread started...");
        int sum = 0;
        for (int i = 0; i <= upper; i++) {
            sum += i;
        }
        System.out.println("Sum is:" + sum);
        sumValue = sum;
    }

    public Integer getSumValue() {
        return sumValue;
    }
}

Upvotes: 2

Powerlord
Powerlord

Reputation: 88796

This code

sumValue = sum;

overwrites Summation's sumValue with a new reference rather than updating the value of the reference that's already there.

If you want to return values from a thread, you need to use a Callable instead of a Runnable.

However, Callables can't be used using Thread directly. Instead you have to use an ExecutorService.

The easiest way to do this would be:

ExecutorService service = Executors.newSingleThreadExecutor();
Future<Integer> future = service.submit(new Summation());
Integer sumValue = future.get(); // The Future equivalent of join

Note that this uses a Future<Integer>, which is a value that will be returned in the future. We use get which blocks unless the Future finishes processing.

Note that you'll have to redesigned Summation to implement Callable<Integer> instead of Runnable, and change public void run() to public Integer call() and return sum; (or sumValue).

Upvotes: 1

Gregory Basior
Gregory Basior

Reputation: 290

Inside the thread you are assigning SumValue to a new Object, so outside of the thread it is still null. If you plan on running this thread multiple times to get multiple sums, try storing the sums in a Map where the key is the upper number and the value is the sum.

So:

      Map<Integer,Integer> sumMap = new TreeMap<Integer,Integer>();
      Thread thread = new Thread(new Summation(upper, sumMap));


public Summation(int upper, Map<Integer,Integer> sumMap) {
    this.upper = upper;
    this.sumMap= sumMap;
}

public void run() {
    System.out.println("Thread started...");
    int sum = 0;
    for (int i = 0; i <= upper; i++) {
        sum += i;
    }
    System.out.println("Sum is:" + sum);
    sumMap.put(upper,sum);
}

Upvotes: 1

reckter
reckter

Reputation: 596

In the constructor of Summation you set the field sumValue. Then in the function run you set the field sumValue again:

sumValue = sum;

But you're setting the field to a new Integer instance. You are not setting the old Integer instance to a new value. That is why the sumValuein the main thread isn't changing, it's never been set to anything but null.

Upvotes: 1

Related Questions