Java 线程应用程序将重复行写入日志文件
我已经编写了一个多线程应用程序,它使用regex分析数据库中的行并适当地更新它们。我正在将每一行写入一个日志文件以用于日志记录。我注意到同一行被多次写入日志文件…有时甚至超过15次。下面是代码片段 设置ThreadPoolExecuter:Java 线程应用程序将重复行写入日志文件,java,regex,multithreading,Java,Regex,Multithreading,我已经编写了一个多线程应用程序,它使用regex分析数据库中的行并适当地更新它们。我正在将每一行写入一个日志文件以用于日志记录。我注意到同一行被多次写入日志文件…有时甚至超过15次。下面是代码片段 设置ThreadPoolExecuter: private static BlockingQueue<Runnable> worksQueue = new ArrayBlockingQueue<Runnable>(blockingQueueSize); private stat
private static BlockingQueue<Runnable> worksQueue = new ArrayBlockingQueue<Runnable>(blockingQueueSize);
private static ThreadPoolExecutor exec = new ThreadPoolExecutor(threadPoolSize, threadPoolSize, 10, TimeUnit.SECONDS, worksQueue);
UpdateMember(仅显示run和writeToLog方法):
公共类UpdateMember实现可运行{
结果集rs;
连接接头;
文件编写器;
公共更新成员(结果集、连接连接、FileWriter fw){
这1.rs=rs;
this.conn=conn;
this.fw=fw;
}
@凌驾
公开募捐{
试一试{
(a-a-a-zA-Z-Z\\\\...........)10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10 10“;QC | PC |魁|魁北克| SK |萨斯克|萨斯喀彻温| YT |育空|育空地区(\\s(?CA | CAN | canda))?”;
Pattern=Pattern.compile(regex,Pattern.CASE不区分大小写);
BigDecimal memrecno=rs.getBigDecimal(2);
String addressLineTwo=rs.getString(4);
字符串addressLineThree=rs.getString(5);
字符串地址linefour=rs.getString(6);
BigDecimal attrrecno=rs.getBigDecimal(9);
字符串addressBeingParsed=“”;
字符串city=null;
字符串省=空;
字符串country=null;
布尔usingAddressThree=假;
布尔值usingAddressFour=false;
如果(addressLineFour==null){
if(addressLineThree==null){
city=“未知”;
}
其他的
{
addressBeingParsed=addressLineThree;
usingAddressThree=真;
}
}
其他的
{
addressBeingParsed=addressLineFour;
usingAddressFour=真;
}
如果(使用地址三| |使用地址四){
Matcher Matcher=pattern.Matcher(正在解析的地址);
//如果找到匹配项
if(matcher.matches()){
城市=匹配器组(“城市”);
省=匹配器组(“州”);
国家=匹配器组(“国家”);
if(city==null | | city.isEmpty()){
//城市只是字母字符和空间
字符串cityRegex=“(?^[a-zA-Z\\s\\.]+$)”;
Pattern cityPattern=Pattern.compile(cityRegex,Pattern.Pattern不区分大小写);
如果(使用AddressFour&&(addressLineThree!=null)&&!addressLineThree.isEmpty()){
Matcher cityMatcher=cityPattern.Matcher(addressLineThree);
if(cityMatcher.matches()){
城市=城市匹配器组(“城市”);
}
其他的
{
city=“未知”;
}
}
else if(使用AddressThree&&(addressLineTwo!=null)&&!addressLineTwo.isEmpty()){
Matcher cityMatcher=cityPattern.Matcher(addressLineTwo);
if(cityMatcher.matches()){
城市=城市匹配器组(“城市”);
}
其他的
{
city=“未知”;
}
}
其他的
{
city=“未知”;
}
}
if(province!=null&&!province.isEmpty()){
省=createProvinceCode(省);
}
}
其他的
{
city=“未知”;
}
}
//更新数据库中的属性
布尔值success=updateRow(memrecno、attrecno、市、省);
字符串logLine=memrecno.toString()+“|”+attrrecno.toString()+“|”+addressLineTwo+“|”+addressLineTwo+“|”+addressLineFour+“|”+“+city+“|”+“+country+“|”+“+success+“|”+String.valueOf(Thread.currentThread().getId());
写日志(logLine);
}
捕获(例外e)
{
e、 printStackTrace();
}
}
私有同步的void writeToLog(字符串行){
试一试{
fw.write(第+行“\r\n”);
fw.flush();
}
捕获(IOEX异常)
{
System.out.println(“写入日志文件时出错。”+ex.getMessage());
}
}
}
我不知道线程是否也多次调用updateRow方法,但我假设它们也在调用,这真的很糟糕
你知道为什么要这样做吗?我认为ResultSet不是线程安全的。从代码中,您应该首先获取值,然后将值而不是rs传递到线程中。看起来在
writeToLog()
中可能有多个线程,除非它已同步。您尝试过同步吗?很抱歉,我应该共享writeToLog()方法。我更新了我的问题,将其包括在内。它是同步的。谢谢……看起来你是对的。结果集不是线程安全的。既不是报表也不是准备好的报表。我可以创建一个新的ResultSet对象并将其分配给rs吗?或者我会因为通过引用传递而遇到问题吗?我不知道为什么必须通过结果
rs = ps.executeQuery();
while (rs.next()) {
exec.execute(new UpdateMember(rs, conn, fileWriter));
if (worksQueue.size() == blockingQueueSize) {
//reach the maximum, stop refill
for (;;) {
Thread.yield();
//wait until the size of queue reached the minimum
if (worksQueue.size() == 0) {
//start refill
break;
}
}
}
}
public class UpdateMember implements Runnable {
ResultSet rs;
Connection conn;
FileWriter fw;
public UpdateMember(ResultSet rs, Connection conn, FileWriter fw) {
this.rs = rs;
this.conn = conn;
this.fw = fw;
}
@Override
public void run() {
try {
String regex = "((?<city>[a-zA-Z\\s\\.]+)\\s)?(?<provState>AB|ALB|Alta|alberta|BC|B\\.C\\.|British Columbia|LB|Labrador|MB|Man|Manitoba|N[BLTSU]|Nfld|NF|Newfoundland|NWT|Northwest Territories|Nova Scotia|New Brunswick|Nunavut|ON|ONT|Ontario|PE|PEI|Prince Edward Island|QC|PC|QUE|QU|Quebec|SK|Sask|Saskatchewan|YT|Yukon|Yukon Territories)(\\s(?<country>CA|CAN|CANADA))?$";
Pattern pattern = Pattern.compile(regex, Pattern.CASE_INSENSITIVE);
BigDecimal memrecno = rs.getBigDecimal(2);
String addressLineTwo = rs.getString(4);
String addressLineThree = rs.getString(5);
String addressLineFour = rs.getString(6);
BigDecimal attrrecno = rs.getBigDecimal(9);
String addressBeingParsed = "";
String city = null;
String province = null;
String country = null;
boolean usingAddressThree = false;
boolean usingAddressFour = false;
if (addressLineFour == null) {
if (addressLineThree == null) {
city = "Unknown";
}
else
{
addressBeingParsed = addressLineThree;
usingAddressThree = true;
}
}
else
{
addressBeingParsed = addressLineFour;
usingAddressFour = true;
}
if (usingAddressThree || usingAddressFour) {
Matcher matcher = pattern.matcher(addressBeingParsed);
// if matches are found
if (matcher.matches()) {
city = matcher.group("city");
province = matcher.group("provState");
country = matcher.group("country");
if (city == null || city.isEmpty()) {
// cities are alpha characters and spaces only
String cityRegex = "(?<city>^[a-zA-Z\\s\\.]+$)";
Pattern cityPattern = Pattern.compile(cityRegex, Pattern.CASE_INSENSITIVE);
if (usingAddressFour && (addressLineThree != null) && !addressLineThree.isEmpty()) {
Matcher cityMatcher = cityPattern.matcher(addressLineThree);
if (cityMatcher.matches()) {
city = cityMatcher.group("city");
}
else
{
city = "Unknown";
}
}
else if (usingAddressThree && (addressLineTwo != null) && !addressLineTwo.isEmpty()) {
Matcher cityMatcher = cityPattern.matcher(addressLineTwo);
if (cityMatcher.matches()) {
city = cityMatcher.group("city");
}
else
{
city = "Unknown";
}
}
else
{
city = "Unknown";
}
}
if (province != null && !province.isEmpty()) {
province = createProvinceCode(province);
}
}
else
{
city = "Unknown";
}
}
// update attributes in database
boolean success = updateRow(memrecno, attrrecno, city, province);
String logLine = memrecno.toString() + "|" + attrrecno.toString() + "|" + addressLineTwo + "|" + addressLineThree + "|" + addressLineFour + "|" + city + "|" + province + "|" + country + "|" + success + "|" + String.valueOf(Thread.currentThread().getId());
writeToLog(logLine);
}
catch (Exception e)
{
e.printStackTrace();
}
}
private synchronized void writeToLog(String line) {
try {
fw.write(line + "\r\n");
fw.flush();
}
catch (IOException ex)
{
System.out.println("Error writing to log file. " + ex.getMessage());
}
}
}