0

I have the following class:

public class Example(

   private String id;
   private ArrayList<String> docs = new ArrayList();

   public Example(string startid){
      id = startid;
      docs = null;
   }

   public void myMethod(String externalID){

      Example myExample = new Example(externalID);

}

If I understand well when I call myMethod, it will create an instance of Example called myExample with id = externalID and docs = null.

What I want this class to do is: Call myMethod simultaneously from external points that will create an instance (myExample) and make sure that the external calls cannot overwrite any of myExample's variables (thread safe?) What I also want it to do is to populate the docs array from an external call within the appropriate myExample instance. Is this possible at all or do I have to pass the ArrayList with the startid at the same time?

3
  • What are you doing with your myExample var? Can't you make myMethod return it? That way, any external point will manage its own instance as it needs. Commented Mar 7, 2013 at 11:19
  • myExample has local visibility in the method myMethod, it is not visible at all to external call. Or do you plan to have myExample as instance or class variable ? Commented Mar 7, 2013 at 11:20
  • I'm not sure what you want to achieve using myMethod why don't you just call the constructor to create a new object. I see no benefit in using this method, and btw. - as mentioned obove - the created Example object cannot be used outside the method. Commented Mar 7, 2013 at 11:28

2 Answers 2

1

Based on Benoit's thoughts of what you want to achive, I think the best way is using a Map (or ConcurrentMap if you want thread-safety) :

ConcurrentMap<String, List<String>> myData = new ConcurrentHashMap<>();

This way you can address any list by the id you provided.

List<String> myList = myData.get(id);

If you want to restrict the list's accessors (e.g. only provide the add method) you need to encapsulate the list in a class :

public final class Example {
    private final List<String> docs = new ArrayList<>();

    public boolean addDoc(final String doc) {
        return docs.add(doc);
    }
}

And then use the Map as follows :

ConcurrentMap<String, Example> myData = new ConcurrentHashMap<>();

And add docs like that :

myData.get(id).addDoc(myDoc);

Hope this helps...

On the topic discussed in comments : setting variables

You have a class like this :

public class Example {
    public String var;
}

And an instance like this

Example ex = new Example();

You can set the value with

ex.var = "abc";

With a calss like this

public class Example {
    private String var;
    public void setVar(String var) {
        this.var = var;
    }
}

use

ex.setVar("abc");

Managing multiple instances :

1) Your web-service get the information with an id

2) Your server-application stores a Map of instances and you can access it through the ID (see Map example above). In the web-Service you call

Example ex = ReportHolder.getReport(id);

Assuming a class like this :

public class ReportHolder {
    private static ConcurrentMap<String, Example> map = new ConcurrentMap<>();
    public static Example getReport(final String id) {
        return map.get(id);
    }
}

3) Then you can manipulate the instance.

Make sure you understand the terms variable, class, instance and static correctly. Otherwiese it will be hard to understand why your error happened.

Sign up to request clarification or add additional context in comments.

9 Comments

I'm confused. What I would like to achieve is: call a jar file via a HTTP call and pass in variables, e.g ID and docs. Each new incoming webservice call will spawn a new instance of the class.
I didn't know we are talking about web-services. A web-service request is handled by one thread normally, so different requests are handled by different threads. That means you would always create a new Example object by calling the web-service. Which framework you are using (how do you implemented the web-service)? The question is what do you want to do with the Example object after you created it?
I'm running my code in a third party application called BI Publisher. When a report is executed through a web service call, the report kicks off the java app. At the moment the app is working when one web service call comes in at a time but when more than one at the same time, the static variables are being overwritten hence the wrong output is generated. So the web service call calls a report, the report then calls the Java class and feeds in various attributes using static setter methods. Somehow I need to make sure that when 2 reports are running, the variables are not mixed up.
I guess your problem are the static variables. A static variable is not bound to an instance it is bound to the class. If thread1 created an instance and thread2 created one at the same time you have different objects, but the static variables will be shared. If thread1 sets a static var and thread2 sets the same var a bit later thread1 will get the value thread2 set. That's a race condition. To avoid this, don't use static variables. Why did you make them static?
I didn't I'm just here to fix it.:) What I don't understand is, how to pass in variables inside an instance? Because as I mentioned the variables are set with separate setters so, once the first variable is set and the class is instantiated how do you set the second variable on the same class?
|
1

You understand incorrectly.

In order to call myMethod you need to have an Example instance already made, and calling myMethod will instantiate a new instance with an externalId, and them immediately discard it.

From what I understand what you want is the following:

public class Example {

  // Final so it can't be modified once set.
  private final String id;

  // Final so it can't be switch to a different list.
  // Public so others can add to it and have acces to List methods.
  // Synchronized so acces to it from multiple threads is possible.
  // Note: You should probably make this private and have a getList() method that
  //       returns this instance to have nice encapsulation.
  public final List<String> docs = Collections.synchronizedList(new ArrayList());

  // Make default constructor private to force setting the startId.
  private Example() {}

  public Example(final String startId){
     this.id = startId;
  }
}

1 Comment

Thanks Benoit. Will each instance of the class have it's own List? Can I address a specific instance to add to the list? e.g. based on id?

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.