Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to keep an object parameter unchanged in a Runnable Class in Java?

I have a Runnable class like:

Class R1 implements Runnable {
  private static final Log LOGGER = LogFactory.getLog(R1.class);
  private final ObjectClass obj;
  private final SomeService service;

  public R1(ObjectClass obj, SomeService service) {
     this.obj = obj;
     this.service = service;
  }

  @override
  public void run() {
    String value = this.obj.getSomeValue();
    LOGGER.debug("Value is " + value);
    // some actions, such as:
    // service.someMethod(obj);
  }
}

I use a ExecutorService object to execute R1 and put R1 in a queue. But later outside R1 I change the value in the ObjectClass that I passed in R1 so the the actions in R1 after getSomeValue() aren't behaving as I expected. If I want to keep the value of ObjectClass object in R1 unchanged what can I do? Suppose the object is big and has a lot of get and set methods.

To make the problem clearer, I need to pass the obj into a service class object which is also used as a parameter in the runnable class. I have changed the original codes accordingly.

like image 220
newguy Avatar asked Nov 04 '22 14:11

newguy


2 Answers

As per comments, apparently my suggested solution has problems.

As such, follow the other suggestions about creating a new instance and copying the properties you require across. Or create a lightweight data object that holds the properties you require. Either way, I believe you need 2 instances to do what you want.


I suggest you could implement clone method that creates a new instance.

http://download.oracle.com/javase/1,5,0/docs/api/java/lang/Cloneable.html

The problem here is that you have passed the instance into your R1class, but it is still the same single instance, so changes to it will affect everything else. So, implementing a clone method will allow you to easily create a copy of your instance that can be used in your R1 class, while allowing you to make further changes to your original.

In your R1 class,

public R1(ObjectClass obj) {
   //this.obj = obj;
   this.obj = obj.clone();
}

P.S. you must implement this method yourself. It won't just automatically give you a deep copy.

like image 130
Daryl Teo Avatar answered Nov 09 '22 09:11

Daryl Teo


Depending on the nature of your program, there are a couple options.

You could "Override Clone Judiciously" (Item 11 in Effective Java) and clone the object before handing it to the runnable. If overriding clone doesn't work for you, it might be better to do one of the following:

  1. Create a new instance of the object manually and copy the values from obj.
  2. Add a subset of the data contained in obj. So instead of passing obj into the constructor, you would pass in someValue. I would advocate this method, so that you only supply R1 with the data it needs, and not the entire object.

Alternatively, if it doesn't matter that the data in obj changes before R1 is executed, then you only need to make sure that obj doesn't change while R1 is executing. In this case, you could add the synchronize keyword to the getSomeValue() method, and then have R1 synchronize on obj like so:

@Override
public void run() {
  synchronize (obj) {
    String value = obj.getSomeValue();
  }
  // some actions.
}
like image 26
Neil Traft Avatar answered Nov 09 '22 11:11

Neil Traft