在多线程记录中,字符串缓冲区中未显示完整数据。

huangapple go评论59阅读模式
英文:

Not seeing full data in the string buffer in mutli thread logging

问题

我正在使用 ThreadLocal StringBuffer 将整个日志存储,以便在每个测试用例执行结束时将其移动到 kibana。但当我并行运行测试用例时,日志丢失了一些条目。
在将日志添加到 StringBuffer 之前,我将其写入文件,并在日志文件中看到所有条目,但在 StringBuffer 中看不到。

任何想法都非常感谢。

我尝试过 String Builder,但没有运气。尝试过使其同步,但还是没有运气。我尝试将日志条目写入文件,然后移动到字符串缓冲区,我在那里看到了所有的条目,但在字符串缓冲区中没有得到所有的条目。

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 + "!!");
    }
}

从我的黄瓜测试中,我们从每个线程调用上述 callingMethod 方法。

我运行了 10 个并行线程,当我从所有 10 个线程的末尾打印 msg 时,结果是不同的,我看到对于某些线程,它丢失了前几个条目。

我尝试过将 addMsg 设为同步,但还是没有运气。在单线程执行中,日志是正确的,当我在 eclipse 中使用调试时,日志会像预期的那样正常显示。

英文:

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&lt;StringBuffer&gt; msg;
    public static void init() {
         msg = new ThreadLocal&lt;StringBuffer&gt;() {
            @Override
            protected StringBuffer initialValue() {
                return new StringBuffer();
            }
     };

     public static void addMsg(String msg) {
          msg.get().append(msg + &quot;\r\n&quot;);
            System.out.println(msg);
    }
}

public class CallingClass(){
    public void callingMethod(String threadName){
       Messages.init();
       Messages.addMsg(&quot;Hi&quot;);
       Messages.addMsg(&quot;This&quot;);
       Messages.addMsg(&quot;Is&quot;);
       Messages.addMsg(&quot;Testing&quot;);
       Messages.addMsg(&quot;For&quot;);
       Messages.addMsg(&quot;Multi&quot;);
       Messages.addMsg(&quot;Thread&quot;);
       Messages.addMsg(&quot;UI&quot;);
       Messages.addMsg(threadName + &quot;!!&quot;);
    }
}

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.

答案1

得分: 0

多个线程调用 Messages.init()

第一次调用 init 时,msg 的先前值为 null,将被新的 ThreadLocal 替换。

下一次调用 init 时,先前的值将被 新的 ThreadLocal 副本 替换,有效地丢弃了先前使用/创建的所有 StringBuffer 对象。

再次调用时也是如此...

init 方法没有意义,你应该摆脱它(以及对它的所有调用),并且只需像这样定义 msg

static final ThreadLocal<StringBuffer> msg = new ThreadLocal<StringBuffer>() {
            @Override
            protected StringBuffer initialValue() {
                return new StringBuffer();
            }
     };

ThreadLocal 的整个意义在于你只需要一个实例,以便为每个线程提供自己的 StringBuffer

此外,如果访问内容的所有方式都通过这些方法进行,那么不需要 StringBuffer 的同步/线程安全性,你应该改用 StringBuilder

英文:

Multiple threads call Messages.init().

The first time we call init the previous value of null for msg is replaced with a new ThreadLocal.

The next time we call init the previous value is replaced with a new copy of ThreadLocal, effectively discarding all previously used/created StringBuffer objects.

And the same the next time ...

There's no point in that init method and you should get rid of it (and all calls to it) and just define msg like this:

static final ThreadLocal&lt;StringBuffer&gt; msg = new ThreadLocal&lt;StringBuffer&gt;() {
            @Override
            protected StringBuffer initialValue() {
                return new StringBuffer();
            }
     };

The whole point of ThreadLocal is that you only need one instance of it to give each thread their own StringBuffer.

Also, if all access to the content is via those methods, then the synchronization/thread safety of StringBuffer isn't needed and you should use a StringBuilder instead.

huangapple
  • 本文由 发表于 2023年2月16日 02:29:00
  • 转载请务必保留本文链接:https://go.coder-hub.com/75464038.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定