How to be thread safe within an AKKA Actor? - java

My project needs a lot of asynchronous programming so I choose the AKKA platform as with the actor model one can implement asynchronous system just like writing synchronous code without worrying about thread issues. Everything works alright till I meet the following issue(demo code):
import akka.actor.AbstractActor;
import akka.japi.pf.ReceiveBuilder;
import java.util.concurrent.locks.ReentrantLock;
public class TestActor extends AbstractActor {
private final ReentrantLock lock = new ReentrantLock();
#Override
public Receive createReceive() {
return ReceiveBuilder.create()
.matchEquals("lock", s -> lock.lock())
.matchEquals("unlock", s -> lock.unlock())
.build();
}
}
first a "lock" message is send, then a "unlock" message is send, in trying to unlock upon receiving the send message, a IllegalMonitorStateException is thrown, I found out that this is due different messages are actually handled by different threads, s -> lock.lock() and s -> lock.unlock() are executed in different threads so IllegalMonitorStateException is thrown.
My previous assumption is that all actions of an actor is executed in one thread so it is totally thread safe, one dose not have to worry about thread issues. As I use AKKA extensively in my project, now I'm quite concerned and unclear as to when dose one needs to consider thread issue in using AKKA. For example, in following demo code:
public class TestActor1 extends AbstractActor {
private int count = 0;
private Map<Integer, Integer> map = new HashMap<>();
#Override
public Receive createReceive() {
return ReceiveBuilder.create()
.matchEquals("action1", s -> count++)
.matchEquals("action2", s -> getSender().tell(count, getSelf()))
.matchEquals("action3", s -> map.put(3, 2))
.matchEquals("action4", s -> getSender().tell(map.get(3), getSelf()))
.build();
}
}
is the way count and map are used thread safe? Do I need to use volatile for count and use ConcurrentHashMap for map?
ps ======================
The following demo code demonstrates why I need lock in actor, basically I'm implementing a pipeline with back pressure control, once an actor receives too much tasks from upstream actor, it sends an backPressureHi message to the upstream actor to stall the upstream actor execution loop till the back pressure returns to normal and sends a backPressureNormal to resume:
public class PipeLineActor extends AbstractActor {
private final ReentrantLock stallLock = new ReentrantLock();
private Thread executionLoop = new Thread(() -> {
while (true){
stallLock.lock();
stallLock.unlock();
// issue tasks to down stream actors
}
});
#Override
public Receive createReceive() {
return ReceiveBuilder.create()
// down stream actor send "backPressureHi" when back pressure is high to stall the executionLoop
.matchEquals("backPressureHi", s -> stallLock.lock())
// down stream actor send "backPressureNormal" when back pressure resumed normal to resume the executionLoop
.matchEquals("backPressureNormal", s -> stallLock.unlock())
.build();
}
}

Akka is designed to be thread safe. And there is never a need for a locking or synchronisation within an actor. It should not be done.
Akka achieves thread safety by processing a single message at a time. An actor cannot process multiple messages simultaneously. But messages may and will be processed within different threads. (this is the default behaviour but can be changed with a pin dispatcher for example).
From documentation
No concurrency guards such as synchronized or AtomicInteger are needed
since an actor instance processes one message at a time.
To your final questions,
is the way count and map are used thread safe?
Yes, it is thread safe.
Do I need to use volatile for count and use ConcurrentHashMap for map?
No there is no need to do it. See Akka and the Java Memory Model
In layman’s terms this means that changes to internal fields of the
actor are visible when the next message is processed by that actor. So
fields in your actor need not be volatile or equivalent.

Related

Threads getting wrong member variable values

In my project I am facing weird issue with thread.
This issue is only occurring when I am running multiple thread at
once(load testing).
In my project there are multiple Interceptors which intercepts request/response at different level in application and send the request/response to WritetoFile class which writes the details into a flat file using log4j framework.
Below is the sample interceptor code. There are multiple interceptor and each can process in parallel.
/*we have multiple Interceptor class which will pre-process the
request/response and then send it to WritetoFile*/
public class IntercerptorA {
// some code ...
public synchronized void sendRequestToWritetoFile(IRequest request,IResponse response){
WritetoFile wtf = new WritetoFile(); //this class is responsible for writing request/response information into LOG file
wtf.setRequest(request);
wtf.setResponse(response);
Thread thread=new Thread(wtf, "t1");//**assume wtf.getRequest is having "ABC"**
thread.start();
}
}
Now suppose there 2 more Interceptor and has only single line difference in the code.
//For interceptorB
Thread thread=new Thread(wtf, "t2");//**assume wtf.getRequest is having "DEF"**
//For interceptorC
Thread thread=new Thread(wtf, "t3");//**assume wtf.getRequest is having "XYZ"**
Below is the code for WritetoFile class -:
public class WritetoFile implements Runnable{
private volatile IRequest request;
private volatile IResponse response;
public synchronized IRequest getRequest() {
return request;
}
public synchronized void setRequest(IRequest request) {
this.request = request;
}
public synchronized IResponse getResponse() {
return response;
}
public synchronized void setResponse(IResponse response) {
this.response = response;
}
#Override
public void run() {
// I have added synchronized as I was trying to resolve the issue
synchronized(WritetoFile.class){
putItInFile(this.request,this.response);
}
}
private synchronized void putItInFile (IRequest request,IResponse response){
// This is the logger where I find discrepancies
LOGGER.info("Current thread is : "+Thread.currentThread().getName()+" data is"+request);
//some code and method call
}
}
Having said that, now when I am running a single request the LOGGER.info("Current thread is : "+Thread.currentThread().getName()+" data is"+request); line is giving output as below -:
Current thread is t1 data is ABC
Current thread is t2 data is DEF
Current thread is t3 data is XYZ
which is perfectly fine. BUT on running multiple thread at once I am getting sometime wrong output as below -:
Current thread is t1 data is DEF
Current thread is t2 data is DEF
Current thread is t3 data is XYZ
It seems to be that before thread t1 can use the value of "wtf" object in method putItInFile , thread t2 have already reset the wtf value using setter in interceptorB. But what my thinking is, when I am creating new instance WritetoFile class for each thread ,how is thread t2 operation changing thread t1 cache. Please let me know where am I going wrong and what I need to change.
Thanks in advance :)
Using synchronized everywhere does not make a class thread safe.
In your case, as soon as WritetoFile.setRequest(request1) returns there is a window where the lock is not held and any other thread is free to call it before there is an opportunity for it to be used.
Rather than assigning the requests to an instance variable you would be better off adding them to one of the java.util.concurrent queue classes and consuming them from the queue in the Thread.run() method.
Have a look at the java.util.concurrent javadoc as there are heaps of examples in there.
Most likely the DEF request is getting intercepted at two different levels, resulting in the request getting logged twice.
Your problem is a textbook concurrency problem.
You have multiple threads running at the same time that are able to read/write variables.
In order to make sure that these values stay correct you need to add a lock around the code that modifies your variables so that only one thread can modify these variables at any one time.
1) code needs to wait until a method that modifies variables becomes available.
2) when a thread is done modifying a variable and is about to exit the code block it needs to notify the other waiting threads that it is done.
Please read the API and review your code, keeping the above points in mind you should have no problems fixing it.

What is the best way to pass information between threads?

I want to be listening to a server while my program is doing other things, when a message is received from the server I want to interpret it.
I know about threading but not sure completely on how it works. If I have a thread listening for the server how can I pass that data to the main thread for interpretation? What is the best way for the main thread to send data to the server? What is the use of the synchronized modifier?
If I have a thread listening for the server how can I pass that data to the main thread for interpretation? What is the best way for the main thread to send data to the server?
I'd use a BlockingQueue for this. You define a single BlockingQueue such as the LinkedBlockingQueue. Your listener class then calls queue.take() which will wait for your server to call queue.put(). It leaves all of the synchronization, waits, notifies, etc. to the Java class instead of your own code.
What is the use of the synchronized modifier?
I'd do some reading to understand more about this. This is not the sort of thing that can be answered in a short-ish SO response. The Java concurrency tutorial is a good place to start.
If you want synchronous communication between a main thread and a processing thread, you can use a SynchronousQueue.
The idea is that the main thread passes data to the processing thread by calling put(), and the processing thread calls take(). Both are blocking operations.
Note that if you want to send back a result, then things may get a bit more complex as the main thread has to know when the result is ready. A CountDownLatch is a good primitive for this. You can do something like this.
First let's define a datastructure to pass data around:
public class MethodCall {
public final String methodName;
public final Object[] args;
public final CountDownLatch resultReady;
public Object result;
public MethodCall(String methodName, Object[] args) {
this.methodName = methodName;
this.args = args;
this.resultReady = new CountDownLatch(1);
}
public void setResult(Object result) {
this.result = result;
resultReady.countDown();
}
public Object getResult() throws InterruptedException {
resultReady.await();
return result;
}
}
Define the queue to pass data around, visible by both threads:
public SynchronousQueue<MethodCall> methodCalls = new SynchronousQueue<MethodCall>();
To make a call from the main thread to the processing thread and wait for the result:
MethodCall call = new MethodCall(methodName, args);
methodCalls.put(call);
Object result = call.getResult();
In the processing thread, for instance in a run() method, you can then do:
for (;;) {
MethodCall call = methodCalls.take();
Object res = processStuff(call.methodName, call.args);
call.setResult(res);
}
Where processStuff implements your logic. Of course you should deal with exceptions as well, deal with exit cases, change MethodCall to have more specific things than methodName and args and an Object return, etc.
Go through some tutorials for understanding Java Threads.
http://www.journaldev.com/1079/java-thread-tutorial
Your problem seems to be like producer-consumer model, you can use BlockingQueue to achieve this task easily.
Java Blocking Queue

Why is my multi-threaded application being paused?

My multi-threaded application has a main class that creates multiple threads. The main class will wait after it has started some threads. The runnable class I created will get a file list, get a file, and remove a file by calling a web service. After the thread is done it will notify the main class to run again. My problem is it works for a while but possibly after an hour or so it will get to the bottom of the run method from the output I see in the log and that is it. The Java process is still running but it does not do anything based on what I am looking at in the log.
Main class methods:
Main method
while (true) {
// Removed the code here, it was just calling a web service to get a list of companies
// Removed code here was creating the threads and calling the start method for threads
mainClassInstance.waitMainClass();
}
public final synchronized void waitMainClass() throws Exception {
// synchronized (this) {
this.wait();
// }
}
public final synchronized void notifyMainClass() throws Exception {
// synchronized (this) {
this.notify();
// }
}
I originally did the synchronization on the instance but changed it to the method. Also no errors are being recorded in the web service log or client log. My assumption is I did the wait and notify wrong or I am missing some piece of information.
Runnable Thread Code:
At the end of the run method
// This is a class member variable in the runnable thread class
mainClassInstance.notifyMainClass();
The reason I did a wait and notify process because I do not want the main class to run unless there is a need to create another thread.
The purpose of the main class is to spawn threads. The class has an infinite loop to run forever creating and finishing threads.
Purpose of the infinite loop is for continually updating the company list.
I'd suggest moving from the tricky wait/notify to one of the higher-level concurrency facilities in the Java platform. The ExecutorService probably offers the functionality you require out of the box. (CountDownLatch could also be used, but it's more plumbing)
Let's try to sketch an example using your code as template:
ExecutorService execSvc = Executors.newFixedThreadPool(THREAD_COUNT);
while (true) {
// Removed the code here, it was just calling a web service to get a list of companies
List<FileProcessingTask> tasks = new ArrayList<FileProcessingTask>();
for (Company comp:companyList) {
tasks.add(new FileProcessingTask(comp));
}
List<Future<FileProcessingTask>> results = execSvc.invokeAll(tasks); // This call will block until all tasks are executed.
//foreach Future<FileProcessingTask> in results: check result
}
class FileProcessingTask implements Callable<FileResult> { // just like runnable but you can return a value -> very useful to gather results after the multi-threaded execution
FileResult call() {...}
}
------- edit after comments ------
If your getCompanies() call can give you all companies at once, and there's no requirement to check that list continuously while processing, you could simplify the process by creating all work items first and submit them to the executor service all at once.
List<FileProcessingTask> tasks = new ArrayList<FileProcessingTask>();
for (Company comp:companyList) {
tasks.add(new FileProcessingTask(comp));
}
The important thing to understand is that the executorService will use the provided collection as an internal queue of tasks to execute. It takes the first task, gives it to a thread of the pool, gathers the result, places the result in the result collection and then takes the next task in the queue.
If you don't have a producer/consumer scenario (cfr comments), where new work is produced at the same time that task are executed (consumed), then, this approach should be sufficient to parallelize the processing work among a number of threads in a simple way.
If you have additional requirements why the lookup of new work should happen interleaved from the processing of the work, you should make it clear in the question.

Preventing race conditions for message processing

I have a J2EE application that receives messages (events) via a web service. The messages are of varying types (requiring different processing depending on type) and sent in a specific sequence. It have identified a problem where some message types take longer to process than others. The result is that a message received second in a sequence may be processed before the first in the sequence. I have tried to address this problem by placing a synchronized block around the method that processes the messages. This seems to work, but I am not confident that this is the "correct" approach? Is there perhaps an alternative that may be more appropriate or is this "acceptable"? I have included a small snippit of code to try to explain more clearly. .... Any advice / guidance appreciated.
public class EventServiceImpl implements EventService {
public String submit (String msg) {
if (msg == null)
return ("NAK");
EventQueue.getInstance().submit(msg);
return "ACK";
}
}
public class EventQueue {
private static EventQueue instance = null;
private static int QUEUE_LENGTH = 10000;
protected boolean done = false;
BlockingQueue<String> myQueue = new LinkedBlockingQueue<String>(QUEUE_LENGTH);
protected EventQueue() {
new Thread(new Consumer(myQueue)).start();
}
public static EventQueue getInstance() {
if(instance == null) {
instance = new EventQueue();
}
return instance;
}
public void submit(String event) {
try {
myQueue.put(event);
} catch (InterruptedException ex) {
}
}
class Consumer implements Runnable {
protected BlockingQueue<String> queue;
Consumer(BlockingQueue<String> theQueue) { this.queue = theQueue; }
public void run() {
try {
while (true) {
Object obj = queue.take();
process(obj);
if (done) {
return;
}
}
} catch (InterruptedException ex) {
}
}
void process(Object obj) {
Event event = new Event( (String) obj);
EventHandler handler = EventHandlerFactory.getInstance(event);
handler.execute();
}
}
// Close queue gracefully
public void close() {
this.done = true;
}
I am not sure what is the framework (EJB(MDB)/JMS) you are working with. Generally using synchronization inside a Managed Environment like that of EJB/JMS should be avoided(its not a good practice). One way to get around is
the client should wait for the acknowledgement from the server before it sends the next message.
this way you client itself will control the sequence of events.
Please note this won't work if there are multiple client submitting the messages.
EDIT:
You have a situation wherein the client of the web service sends message in sequence without taking into account the message processing time. It simply dumps the message one after another. This is a good case for Queue ( First In First Out ) based solution. I suggest following two ways to accomplish this
Use JMS . This will have an additional overhead of adding a JMS providers and writing some plumbing code.
Use some multitheading pattern like Producer-Consumer wherein your web service handler will be dumping the incoming message in a Queue and a single threaded consumer will consume one message at a time. See this example using java.util.concurrent package.
Use database. Dump the incoming messages into a database. Use a different scheduler based program to scan the datbase (based on sequence number) and process the messages accordingly.
First and third solution is very standard for these type of problems. The second approach would be quick and won't need any additional libraries in your code.
If the events are to be processed in a specific sequence, then why not try adding "eventID" and 'orderID' fields to the messages? This way your EventServiceImpl class can sort, order and then execute in the proper order (regardless of the order they are created and/or delivered to the handler).
Synchronizing the handler.execute() block will not get the desired results, I expect. All the synchronized keyword does is prevent multiple threads from executing that block at the same time. It does nothing in the realm of properly ordering which thread goes next.
If the synchronized block does seem to make things work, then I assert you are getting very lucky in that the messages are being created, delivered and then acted upon in the proper order. In a multithread environment, this is not assured! I'd take steps to assure you are controlling this, rather than relying on good fortune.
Example:
Messages are created in the order 'client01-A', 'client01-C',
'client01-B', 'client01-D'
Messages arrive at the handler in the order 'client01-D',
'client01-B', 'client01-A', 'client01-C'
EventHandler can distinquish messages from one client to another and starts to cache 'client01' 's messages.
EventHandler recv's 'client01-A' message and knows it can process this and does so.
EventHandler looks in cache for message 'client01-B', finds it and processes it.
EventHandler cannot find 'client01-C' because it hasn't arrived yet.
EventHandler recv's 'client01-C' and processes it.
EventHandler looks in cache for 'client01-D' finds it, processes it, and considers the 'client01' interaction complete.
Something along these lines would assure proper processing and would promote good use of multiple threads.

Pattern for executing concurrent tasks just once

I am working on a java server which dispatches xmpp messages and workers execute the tasks from my clients.
private static ExecutorService threadpool = Executors.newCachedThreadPool();
DispatchWorker worker = new DispatchWorker(connection, packet);
threadpool.execute(worker);
Works fine, but i need a bit more than that.
I don't want to execute the same request multiple times.
My worker may start another thread with a backround task also only allowed to run once at a time. A Threadpool in the worker threads.
I can identify the requests by a string and i can also give the backround tasks an id to identify them.
My solution would be a synchronized hashmap where my running tasks are registered with their id. The reference of the map will be passed to the worker threads that they remove their entry when they finished.
Feels a bit clumsy this solution so i wanted to know if there are more elegant patterns/best practices.
best regards, m
This is exactly what Quartz does (although it does a lot more, like scheduling jobs in the future).
You can use a Singleton thread pool or pass the thread pool as an argument. (I would have the pool final)
You can use a HashSet to guard adding duplicate tasks.
I believe using Map is okay for this. But instead of synchronized HashMap you can also use ConcurrenHashMap which allows you to specify concurrency levels, i.e. how many thread can work with map at the same time. And also it has atomic putIfAbsent operation.
I would use queues and daemon worker threads that are always running and wait for something to arrive in the queue. This way it is guaranteed, that only one worker is working on a request.
If you only want one thread to run, turn POOLSIZE down to 1, or use newSingleThreadExecutor.
I do not quite understand your second requirement: do you mean only 1 thread is allowed to run as background task? If so, you could create another SingleThreadExecutor and use that for the background task. Then it would not make too much sense to have POOLSIZE>1, unless the work done in the background thread is very short compared to that done in the worker itself.
private static interface Request {};
private final int POOLSIZE = 10;
private final int QUEUESIZE = 1000;
BlockingQueue<Request> e = new LinkedBlockingQueue<Request>(QUEUESIZE);
public void startWorkers() {
ExecutorService threadPool = Executors.newFixedThreadPool(POOLSIZE);
for(int i=0; i<POOLSIZE; i++) {
threadPool.execute(new Runnable() {
#Override
public void run() {
try {
final Request request = e.take();
doStuffWithRequest(request);
} catch (InterruptedException e) {
// LOG
// Shutdown worker thread.
}
}
});
}
}
public void handleRequest(Request request) {
if(!e.offer(request)) {
//Cancel request, queue is full;
}
}
At startup-time, startworkers starts the workers (surprise!).
handleRequest handles requests coming from a webservice, servlet or whatever.
Of course you need to adapt "Request" and "doStuffWithRequest" to your need, and add some additional logic for shutdown etc.
We originally wrote our own utilities to handle this, but if you want the results memoised, then Guava's ComputingMap encapsulates the initialisation by one and only one thread (with other threads blocking and waiting for the result), and the memoisation.
It also supports various expiration strategies.
Usage is simple, you construct it with an initialisation function:
Map<Long, Foo> cache = new MapMaker().makeComputingMap(new Function<Long, Foo>() {
public Foo apply(String key) {
return … // init with expensive calculation
}
});
and then just call it:
Foo foo = cache.get("key");
The first thread to ask for "key" will be the one who performs the initialisation

Categories

Resources