0

I don't quite know how to explain the situation, I will try to be as clear as possible.

I am currently writing a web-application, using Spring to manage the beans. Obviously, more than one people will use this application. Each user has a set of data related to himself. My problem comes with some poor design I introduced when I just entered the development field. Here is the case:

@Component
public class ServiceClass implements IService    {

@Autowired
private Dependency   firstDependency;

@Autowired
private UsefulObject secondDependency;

private DataSet      dataSet; // THIS LINE IS IMPORTANT

public void entryPoint(String arg1, int arg2, Structure arg3)    {
    /* Query data from a database specific from the project (not SQL
    oriented. I absolutely need this information to keep going. */
    dataSet = gatherDataSet(String ar1);

    /* Treat the data */
    subMethodOne(arg1);
    subMethodTwo(arg2);
    subMethodThree(arg3);
}

private subMethodOne(String arg1)    {
    // Do some things with arg1, whatever
    subSubMethod(arg1);
}

private subSubMethod(String arg1)    {
    /* Use the DataSet previously gathered */
    dataSet.whateverDoing();
}

... // Functions calling sub-methods, using the DataSet;

As every user would have a different dataSet, I thought it would be good to call it at the beginning of every call to my service. In the same way, as is it used very deep in the call hierarchy, I thought it would be a good idea to store it as an attribute.

The problem I encounter is that, when two users are going through this service nearly simultaneously, I have a cross-data issue. The following happens:

  • First user comes in, calls gatherDataSet.
  • Second user comes in, calls gatherDataSet. First user is still treating !
  • First user still uses the dataSet object, which was overrid by Second user.

Basically, the data first user makes use of become false, because he uses data from the second user, which came in short after him.

My questions are the following:

  • Are there design pattern / methods to avoid this kind of behavior ?
  • Can you configure Spring so that he uses two instances fo two users (and so on), to avoid this kinf od problems ?

Bonus: (Kind of unrelated) How to implement a very large data mapper ?

Yassine Badache
  • 1,810
  • 1
  • 19
  • 38

4 Answers4

1

The easiest solution is simply to not store the dataset in a class field.

Instead, store the dataset in a local variable and pass it as an argument to other functions, this way there will not be any concurrency problems, as each call stack will have it's own instance.

Example:

public void entryPoint(String arg1, int arg2, Structure arg3) {
    // Store the dataset in a local variable, avoiding concurrency problems
    Dataset dataSet = gatherDataSet(String ar1);

    // Treat the data passing dataset as an argument
    subMethodOne(arg1, dataset);
    subMethodTwo(arg2, dataset);
    subMethodThree(arg3, dataset);
}
ESala
  • 6,878
  • 4
  • 34
  • 55
1

Object member variables (fields) are stored on the heap along with the object. Therefore, if two threads call a method on the same object instance and this method updates object member variables, the method is not thread safe.

However, If a resource is created, used and disposed within the control of the same thread, and never escapes the control of this thread, the use of that resource is thread safe.

With this in mind, change your design. https://books.google.co.in/books?isbn=0132702258 is a must read book for coming up with good java based software design

More stackoverflow links: Why are local variables thread safe in Java , Instance methods and thread-safety of instance variables

Spring promotes singleton pattern and (it is the default bean scope). Spring configuration for having two service class objects for two different users is called prototype bean scoping, but should be avoided as far as possible.

Consider the usage of in-memory Map or an external no-sql datastore or an external relational database

gargkshitiz
  • 2,130
  • 17
  • 19
1

Can you configure Spring so that he uses two instances fo two users (and so on), to avoid this kinf od problems ?

You already mentioned correctly, that the design decisions you took are flawed. But to answer your specific question, which should get your use-case to work correctly, but at a impact to performance cost:

You can set spring beans to various scopes (relevant for your usecase: prototype / request or session), which will modify when spring beans get instanced. The default behaviour is one bean per spring container (singleton), hence the concurrency issues. See https://docs.spring.io/spring/docs/3.0.0.M3/reference/html/ch04s04.html

-1

Use synchronized modifier for it. As "Synchronization plays a key role in applications where multiple threads tend to share the same resources, especially if these resources must keep some kind of sensitive state where manipulations done by multiple threads at the same time could lead the resource to become in an inconsistent state."

public void someMethod() {

  synchronized (object) {
    // A thread that is executing this code section
    // has acquired object intrinsic lock.

    // Only a single thread may execute this
    // code section at a given time.
  }

}
Pravin
  • 1