1

I seen already : How can I pass a parameter to a Java Thread?

But I don't know how exactly use that. So I made easy samle code to save your precious time :

class ThreadParam implements Runnable { 
static int c;

public ThreadParam(int a, int b){
    int c = a+b;
}

public void run(){
    System.out.println(c);
}

}

public class ThreadParamTest {
public static void main(String args[]){
    Runnable r = new ThreadParam(1000,2000);
    new Thread(r).start();  
}   
}

Why is this result 0 ? I think that should be 3000. Maybe the variable "int c" isn't dispatch to run() method. How can I solve this issue?

Community
  • 1
  • 1
ton1
  • 7,238
  • 18
  • 71
  • 126

5 Answers5

6

I think the choice of "static int c" is incorrect as it means that all instances of ThreadParam will "share" (and poorly at that) a common value for c. That is to stay, if you have 2 separate ThreadParams going simultaneously, one of them is likely present the "wrong" value for C. Consider...

class BadThreadParam implements Runnable {
    static int c;

    public BadThreadParam( int a, int b ) {
        c = a + b;
    }

    public void run() {
        System.out.println( c );
    }
}

class ImmutableThreadParam implements Runnable {
    private final int c;

    public ImmutableThreadParam( int a, int b ) {
        c = a + b;
    }

    public void run() {
        System.out.println( c );
    }
}

public class BadThreadParamTest  {
    public static void main( String[] args ) {
        BadThreadParam shouldBe3 = new BadThreadParam( 1, 2 );
        BadThreadParam shouldBe5 = new BadThreadParam( 3, 2 );
        shouldBe3.run();  // Expect 3 but is 5.  WTF?
        shouldBe5.run();  // Expect 5.

        ImmutableThreadParam expect3 = new ImmutableThreadParam( 1, 2 );
        ImmutableThreadParam expect5 = new ImmutableThreadParam( 3, 2 );
        expect3.run();  // Expect 3.
        expect5.run();  // Expect 5.
    }
}

If you make the "c" local to the instance, you overcome the "2 separate ThreadParams are affecting the same value" problem. If you make the "private int c" final, you are avoiding the need for synchronization. If you need to mutate "c" down in the run (or from the outside), now you are entering the world of synchronization...

class ThreadSafeMutableThreadParam implements Runnable {
    private int c;

    public ThreadSafeMutableThreadParam( int a, int b ) {
        c = a + b;
    }

    public synchronized void setC( int c ) {
        this.c = c;
    }

    public synchronized int getC() {
        return c;
    }

    public void run() {
        System.out.println( getC() );
    }
}

Other than that, tuxdna's is correct in describing how you "pass params to a Runnable". The Runnable is inconsequential; you are passing params to a class (however you achieve that). If you need them available down in a run(), you need to be aware of synchronization.

Bob Kuhar
  • 10,838
  • 11
  • 62
  • 115
5

c should not be static and should be assigned in your constructor. In your example, you've assigned to a variable c, not the field.

Here is the corrected code:

class ThreadParam implements Runnable { 
private int c;

public ThreadParam(int a, int b){
    this.c = a+b;
}

public void run(){
    System.out.println(c);
}

}
Xavier Delamotte
  • 3,519
  • 19
  • 30
4

The result is 0 because in constructor you're not actually assigning new value to static int c, but you're assigning it to local variable c.

Change int c into c in constructor.

Andrew Logvinov
  • 21,181
  • 6
  • 52
  • 54
  • 1
    +1 Also, chances are the poster does _not_ want the `c` field to be static. This means that all instances of `ThreadParam` share the same field. – Gray Dec 17 '13 at 17:38
  • Can I ask you one more question? in my example code, in run() method, How can I print the variable "a"? I want to show that. – ton1 Dec 17 '13 at 17:43
  • 1
    You'll need to store `a` as another field (not static) in your `ThreadParam` class @user3100921. Then you can print it. – Gray Dec 17 '13 at 17:51
3

Your 'c' variable is defined twice: once at the class level (with a static modifier) and once in the ThreadParam constructor. Remove the 'static' on the class field and remove the 'int' inside the constructor.

Xavier Coulon
  • 1,580
  • 10
  • 15
2

Runnable is only an interface that requires you to define a run() method, nothing more nor less. So, essentially, you are free to declare your class constructor any way you want ( you are passing two integers a and b) to be able to access them from run() method.

Also you are defining a local variable in the constructor that is destroyed after the constructor has finished. Which leaves your static int c value to be still 0.

Here is the fixed version:

class ThreadParam implements Runnable {
    private int c;

    public ThreadParam(int a, int b) {
        c = a + b;
    }

    public void run() {
        System.out.println(c);
    }

}

public class ThreadParamTest {

    public static void main(String args[]) {
        Runnable r = new ThreadParam(1000, 20000);
        new Thread(r).start();
    }
}

And the output is 21000 ( and not 3000 )

tuxdna
  • 8,257
  • 4
  • 43
  • 61
  • 1
    This code is technically correct, but the "static int c" may not be the best choice here as it means ALL THREADS THAT HAVE a ThreadParam will share this common value. Further, they will see it change each time a new ThreadParam is new'ed up. I would expect this declaration to be, at least "private final int c" to make it instance local and immutable and, thus, thread-safe. If you need to publish "c" outside; create a "public int getC() { return c; } and you are good to go. If "c" is intended to be changed down in the run or from the outside, now you need to protect it with synchronization. – Bob Kuhar Dec 17 '13 at 17:59
  • 1
    @BobKuhar Agreed. It ( `c` ) should be private. However this code is for the reference of original author. Fixed it. – tuxdna Dec 17 '13 at 18:12