2

Here is the code I have:

/* User: koray@tugay.biz 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?

Koray Tugay
  • 20,438
  • 37
  • 155
  • 276
  • 2
    Java is pass by value: http://stackoverflow.com/questions/40480/is-java-pass-by-reference-or-pass-by-value – JB Nizet Feb 21 '15 at 18:03
  • @JBNizet Ok, and I am passing the reference all the time? I am not using a primitive type int. I am passing the reference here. – Koray Tugay Feb 21 '15 at 18:04
  • You're passing null. The Summation class then assigns a non-null value to its own reference. It doesn't modify the original null reference, because references are passed by value: a copy of the reference is passed. – JB Nizet Feb 21 '15 at 18:07
  • @JBNizet I am not passing null. I am passing a reference which points to null, isn't it? I think saying that I am passing 'null' is not entirely correct? I am passing a reference which at the moments points to null. But then I set the same reference to 120. – Koray Tugay Feb 21 '15 at 18:09
  • It's not **the same** reference. It's a copy. A copy of the reference is passed to the Summation constructor, and a new value is assigned to this copy. – JB Nizet Feb 21 '15 at 18:10
  • @JBNizet Ok, but through this copy I am setting the pointed value to 120. – Koray Tugay Feb 21 '15 at 18:10
  • Actually you are passing a reference to the same object. But you are then setting the reference inside the Thread to a new Instance (120) that doesn't mean that ever reference to the old Instance is switched to the new one. – reckter Feb 21 '15 at 18:12

5 Answers5

4

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());
JB Nizet
  • 633,450
  • 80
  • 1,108
  • 1,174
2

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;
    }
}
Community
  • 1
  • 1
antonio
  • 17,130
  • 4
  • 43
  • 56
  • Ah ok now I got it.. Thanks. So I should create my own class that extends Integer maybe which is not immutable? – Koray Tugay Feb 21 '15 at 18:11
  • 1
    You might want to look into using a http://docs.oracle.com/javase/7/docs/api/java/util/concurrent/atomic/AtomicInteger.html – FuriousGeorge Feb 21 '15 at 18:17
1

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.

reckter
  • 576
  • 7
  • 12
  • How can I set the object which is pointed by sumValue to 120? – Koray Tugay Feb 21 '15 at 18:10
  • As pointed out by @antonio in his answer, `Integer` is Immutable, so you can't actually change the value of an Instance. You can however store it in a field and then access it via a getter method in your main method. – reckter Feb 21 '15 at 18:14
1

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);
}
Gregory Basior
  • 290
  • 1
  • 9
1

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).

Powerlord
  • 82,184
  • 16
  • 119
  • 164