在我的项目中,我面临着线程的奇怪问题。
此问题仅在我运行多个线程时发生 一次(负载测试)。
在我的项目中有多个拦截器,它拦截应用程序中不同级别的请求/响应,并将请求/响应发送到WritetoFile类,该类使用log4j框架将详细信息写入平面文件。
以下是示例拦截器代码。有多个拦截器,每个都可以并行处理。
/*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();
}
}
现在假设还有2个Interceptor,并且在代码中只有单行差异。
//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"**
以下是WritetoFile类的代码 - :
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
}
}
话虽如此,现在当我运行单个请求时, LOGGER.info(“当前线程为:”+ Thread.currentThread()。getName()+“data is”+ request); line给出如下输出 - :
当前线程是t1数据是ABC
当前线程是t2数据是DEF
当前线程是t3数据是XYZ
这完全没问题。但是,一旦运行多个线程我得到一些错误的输出,如下所示 - :
当前线程是t1数据是DEF
当前线程是t2数据是DEF
当前线程是t3数据是XYZ
似乎在线程t1可以在方法putItInFile中使用“wtf”对象的值之前,线程t2已经使用interceptorB中的setter重置了wtf值。但我的想法是,当我为每个线程创建新的实例WritetoFile类时,线程t2操作如何更改线程t1缓存。请让我知道我哪里出错了以及我需要改变什么。
提前致谢:)
答案 0 :(得分:0)
很可能DEF请求在两个不同级别被截获,导致请求被记录两次。
答案 1 :(得分:0)
在任何地方使用 synchronized 都不会使类线程安全。
在你的情况下,只要WritetoFile.setRequest(request1)返回,就会有一个窗口没有保持锁定,任何其他线程都可以自由调用它,然后才有机会使用它。
不是将请求分配给实例变量,最好将它们添加到其中一个java.util.concurrent队列类中,并在Thread.run()方法中从队列中使用它们。
看看java.util.concurrent javadoc,因为那里有大量的例子。
答案 2 :(得分:0)
您的问题是教科书并发问题。 您有多个线程同时运行,能够读/写变量。
为了确保这些值保持正确,您需要在修改变量的代码周围添加一个锁,以便任何时候只有一个线程可以修改这些变量。
1)代码需要等待,直到修改变量的方法变为可用。 2)当线程完成修改变量并即将退出代码块时,它需要通知其他等待线程完成它。
请阅读API并查看您的代码,牢记以上几点,您应该没有问题修复它。