我编写了一个多线程应用程序,它使用正则表达式分析数据库中的行并适当地更新它们。我正在将每一行写入日志文件以进行日志记录。我注意到同一行被写入日志文件多次...有时超过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方法,但我假设它们是,而且非常糟糕。
关于它为什么会这样做的任何想法?
答案 0 :(得分:3)
我认为ResultSet不是线程安全的。从您的代码中,您应首先获取值,然后将值而不是rs传递给线程。