I am using ThreadLocal StringBuffer for storing entire log to move it to kibana at the end of each test case execution. But when I am running cases in parallel, the log is loosing some entries. I am writing the log into file before adding it to StringBuffer and I see all entires in the log file but not in the StringBuffer.
Any ideas are much appreciated.
I tried String Builder but no luck. Tried to make synchronized still no luck. I tried writing the log entry into file before moving into string buffer and I see all entire there but not getting all entries in string buffer
public abstract class Messages {
static ThreadLocal<StringBuffer> msg;
public static void init() {
msg = new ThreadLocal<StringBuffer>() {
@Override
protected StringBuffer initialValue() {
return new StringBuffer();
}
};
public static void addMsg(String msg) {
msg.get().append(msg + "\r\n");
System.out.println(msg);
}
}
public class CallingClass(){
public void callingMethod(String threadName){
Messages.init();
Messages.addMsg("Hi");
Messages.addMsg("This");
Messages.addMsg("Is");
Messages.addMsg("Testing");
Messages.addMsg("For");
Messages.addMsg("Multi");
Messages.addMsg("Thread");
Messages.addMsg("UI");
Messages.addMsg(threadName + "!!");
}
}
From my cucumber tests, we call the above method callingMethod from each thread.
I am running 10 parallel threads and the result is different when I print the msg at the end from all 10 threads, I see for some threads it is missing the first few entries.
I tried making addMsg synchronized but still no luck. In a single thread execution, the log is proper and also when I am using debug from eclipse, the log is coming properly as expected.
Multiple threads call
Messages.init().The first time we call
initthe previous value ofnullformsgis replaced with a newThreadLocal.The next time we call
initthe previous value is replaced with a new copy ofThreadLocal, effectively discarding all previously used/createdStringBufferobjects.And the same the next time ...
There's no point in that
initmethod and you should get rid of it (and all calls to it) and just definemsglike this:The whole point of
ThreadLocalis that you only need one instance of it to give each thread their ownStringBuffer.Also, if all access to the content is via those methods, then the synchronization/thread safety of
StringBufferisn't needed and you should use aStringBuilderinstead.