0

I have a JMS object appended to request object and in the doPost() method, the object's get method is being called to get current topic data which will be sent to client in response continuously.

On another user request concurrently, I do not see in the doPost() method, the get message being called or rather am receiving empty/null string from the call.

How to make the method be responsive for concurrent requests/users.

On Debug: While debugging in eclipse, I sometimes see that both threads receive getMessage data alternatively.

<jms:listener-container connection-factory="connectionFactory" task-executor="jmsTaskExecutor" destination-type="topic" concurrency="5">    
    <jms:listener destination="abc.topic" ref="abc" method="receive" />     
</jms:listener-container>

<bean name="jmsTaskExecutor" class="org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor">
    <property name="corePoolSize" value="2"/>
    <property name="maxPoolSize" value="50"/>       
    <property name="threadNamePrefix" value="some-queue-thread"/>
</bean>

<bean id="jmsTopicTemplate" class="org.springframework.jms.core.JmsTemplate">
    <property name="connectionFactory" ref="connectionFactory"/>
    <property name="pubSubDomain" value="true"/>
</bean>


@Component("abc")
public class abc {

private String msg;

public synchronized void receive(String msg){       
    this.msg = msg;     
}


public synchronized String getMessage(){        
    return msg;     
}
}

@Component
@Controller
public class ForwardController extends ServletForwardingController
{   
@Autowired
abc topicObject;

@Override   
@RequestMapping("/xyzPath")
protected ModelAndView handleRequestInternal(HttpServletRequest request, HttpServletResponse response) throws Exception {       
        request.setAttribute("autowired", topicObject);
        request.getRequestDispatcher("/xyz").forward(request, response);
    }        
return null;
}   

@WebServlet("/xyz")
public class xyz extends HttpServlet {
protected void doPost(HttpServletRequest request, HttpServletResponse response) {

abc topicObject =  request.getAttribute("autowired");

while(true){        
    System.out.println("start"+Thread.currentThread.getId());
    String msg = topicObject.getMessage();
    response.getWriter.write(msg);
    System.out.println("stop"+Thread.currentThread.getId());
  }
 }
}

What is the right way to call topicObject.getMessage() concurrently

user3747396
  • 141
  • 12
  • I would strongly suggest (as I did in the other thread) a reconsideration of this architecture. You are sharing a single object with state between threads (the `abc` thing). Thread X overwrites values from Thread Y now image even more threads.. – M. Deinum Jan 08 '15 at 07:03
  • @M.Deinum Could you please elaborate on Thread x, Thread Y overwrites. In the abc class nowhere am I clearing the String msg, so how is it cleared, If there is an overwrite still there should be some data, I am not much clear on this. Also, while debugging I can see that often the data is read(getMessage()) by the two requests. – user3747396 Jan 08 '15 at 07:12
  • You have a single instance of ABC which is shared amongst all threads. State changes are seen by all threads. Not sure if that is what you want. As I already stated earlier you are writing your own framework I strongly suggest take al ook at standard implementations out there. Your solution will kill the server quite quickly. Also it doesn't make sense to forward to a servlet as everything can be done from the controller, you are just adding unnecessary complexity. – M. Deinum Jan 08 '15 at 07:15
  • State changes are that data I receive from JMS that is to be delivered to all subscribers. It is for this reason I put my application on spring so I can share a singleton object for all subscribed users/requests while spring automanages. Server performance is not critical as I can tune latency of pubsub calls to higher number(say 60 instead of 2 secs) – user3747396 Jan 08 '15 at 07:20
  • About the servlet thing instead of sockets or rmi; this is a project dependency for me as I have earlier tried building with sockets which proved untenable for other issues and this framework has a previous version built with rmi instead. The other usecase may be using websockets but they are not as web compliant as servlets. – user3747396 Jan 08 '15 at 07:27
  • It will not perform at all and there is little to tune as your CPU will max out eventually due to your `while (true)` loop as soon as you hit your core limit for processing you are basically out of options. As I stated websockets or comet is mend for this task and will save you time and building your own framework. – M. Deinum Jan 08 '15 at 07:29
  • @M.Deinum The problem nevertheless seems to be with the abc class where a request on reading the message via the topicObject.getMessage() method is causing the clearing of topic's string msg variable. Please let me know if you have an idea to persist the message even after being read.I am unable to open chat due to restrictions at my workplace. I have earlier explored using websockets and comet api but it was a difficult case to fit into the current project goals technically. – user3747396 Jan 08 '15 at 14:57

1 Answers1

0

Remove the @Async annotation. I'm not sure what you intended it to do, but it doesn't do that.

From the Javadoc:

However, the return type is constrained to either void or Future.

And from the Spring framework documentation:

The @Async annotation can be provided on a method so that invocation of that method will occur asynchronously. In other words, the caller will return immediately upon invocation and the actual execution of the method will occur in a task that has been submitted to a Spring TaskExecutor.

In other words, with @Async, the code is not executed immediately but later on another thread, but it returns immediately. So for your getMessage, you have provided a return type that is not supported and leads to undefined behaviour (random even, in your case).

For the receive method, this is also not what you want, because it will defer assignment to message.

Solution: Remove both @Async annotations, and make both methods synchronized so that you correctly publish the change to the message variable which makes it visible in all threads.

Erwin Bolwidt
  • 30,799
  • 15
  • 56
  • 79
  • I have earlier tries Sync. but it was definitely causing only one thread to see data. I therefore made it Async. so that at least occasionally the other thread will be able to read data. – user3747396 Jan 09 '15 at 06:49
  • Remove the @Async, you are using it wrong. And add `synchronized`. I don't know what `Sync` is, but don't go about adding many annotations. `synchronized` is *the* proper way to handle multi-threaded data publication in Java. It will allow all threads to have a consistent view on your `message` – Erwin Bolwidt Jan 09 '15 at 06:55
  • I have made code change as supposed and still the problem remains same. Please let me know if got some idea. – user3747396 Jan 09 '15 at 07:08