线程应用程序将重复行写入日志文件

时间:2014-03-19 20:45:43

标签: java regex multithreading

我编写了一个多线程应用程序,它使用正则表达式分析数据库中的行并适当地更新它们。我正在将每一行写入日志文件以进行日志记录。我注意到同一行被写入日志文件多次...有时超过15次。以下是代码的片段。

设置ThreadPoolExecuter:

private static BlockingQueue<Runnable> worksQueue = new ArrayBlockingQueue<Runnable>(blockingQueueSize);
private static ThreadPoolExecutor exec = new ThreadPoolExecutor(threadPoolSize, threadPoolSize, 10, TimeUnit.SECONDS, worksQueue);

在这部分中,我运行一个查询,然后查看结果:

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;
            }
        }
    }
}

UpdateMember(仅显示run和writeToLog方法):

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());
        }
    }
}

我不知道线程是否也多次调用updateRow方法,但我假设它们是,而且非常糟糕。

关于它为什么会这样做的任何想法?

1 个答案:

答案 0 :(得分:3)

我认为ResultSet不是线程安全的。从您的代码中,您应首先获取值,然后将值而不是rs传递给线程。