一个多线程的PushbackInputStream问题

07-06-25 computerboy
最近在更改以前老项目的代码,出了一个问题,
一部分代码:
class mythread extends Thread{
/**
被start()方法调用的主线程方法.
**/
public void run()
{
dbwr();
}
/**
该方法完成读文件,分析文件,插库,删除文件等全部功能.被线程主方法run()调用.
**/
public synchronized void dbwr()
{
// File news = new File("./store/");
/**
读入(./store/)路径
**/
//File news = new File("./store/");
File news = new File("f:/store/");
/**
存放所读的文件对象.
**/
File arry[];
arry=news.listFiles();
int delete_i=0;
try{
if(arry.length<1){
this.sleep(60000);
sernews.insertthread();
this.stop();this.destroy();
}
this.sleep(1000);
/**
一个用于判断文件是否结束的字节,如果结束,会自动返回-1.
**/
byte temp[]=new byte[1];
/**
读入没条新闻的分类个数.
**/
byte class_total[]=new byte[4];
/**
读入新闻类别.
**/
byte class_id[]=new byte[4];
/**
新闻的日期.
**/

byte news_date[]=new byte[4];
/**
新闻时间
**/
byte news_time[]=new byte[4];
/**
新闻标题的长度.
**/
byte title_total[]=new byte[4];
/**
新闻标题
**/
byte news_title[]=new byte[1024];
/**
新闻内容
**/
byte news_content[]=new byte[653600];
/**
新闻ID号,每条新闻去当前数据库中最大的ID号.
**/
long news_id=0;
for(int i=0;i<arry.length;i++){
delete_i=i;
System.out.print("文件名: "+arry.getName());
if(!arry.isFile()){
arry.delete();
continue;
}
if(arry.length()<40){
System.out.println("非法文件, 被删除!");
arry.delete();
continue;
}

/**
把当前的文件文件流的形式打开.
**/
FileInputStream inputfile=new FileInputStream(arry);
/**
把文件流实例化成一个反压流.
反压流---该流的指针能随文件的读入而移动.而且能够返回以读完的流的指针向量.
**/
PushbackInputStream readfile=new PushbackInputStream(inputfile,653600);
readfile.read(class_total,0,4);
int class_total_l=toInt(class_total);
if(class_total_l>10){
inputfile.close();
readfile.close();
// readfile.unread(class_total,0,4);
System.out.println("非法文件, 被删除!");
arry.delete();
continue;
}
/**
用于存储数据库的链接串,分别是hostname,port,SID,username,password.
**/


Class.forName("oracle.jdbc.driver.OracleDriver");
/**
建立JDBC的连接.
**/
Connection conn= DriverManager.getConnection ("jdbc:oracle:thin:@"+sernews.jdbcdrive,sernews.username,sernews.psw);
// Connection conn= DriverManager.getConnection ("jdbc:oracle:thin:@e5500:1521:ora815","xc","xc");
//Connection conn= DriverManager.getConnection ("jdbc:oracle:thin:@172.20.83.170:1521:ora9i","xc","xc");
conn.setAutoCommit(false);
/**
JDBC声明.
**/
Statement stmt = conn.createStatement();
/**
JDBC返回结果集.
**/
ResultSet result = stmt.executeQuery("select max(news_id) from t_news_class_1");
if(result.next()){
news_id=result.getLong(1);
news_id=news_id+1;
}
int class_id_l;
for(int j=0;j<class_total_l;j++){
readfile.read(class_id,0,4);
class_id_l=toInt(class_id);
stmt.execute("insert into t_news_class_1(news_id,news_class_id) values("+news_id+","+class_id_l+")");
// stmt.execute("insert into t_news_class_1_all(news_id,news_class_id) values("+news_id+","+class_id_l+")");
}

readfile.read(news_date,0,4);
/**
把字节型的日期转换成一个整形的数值.
**/
int lDate_value=toInt(news_date);
readfile.read(news_time,0,4);
/**
把字节型的时间转换成一个整形的数值.
**/
int lTime_value=toInt(news_time);
/**
把整型的日期转换成一个字符.
**/
String sundate=String.valueOf(lDate_value);
/**
把整型的时间转换成一个字符.
**/
String suntime=String.valueOf(lTime_value);
int len=suntime.length();
if(len<6)
{
for(int j=0;j<(6-len);j++)
suntime="0"+suntime;
}

computerboy
2007-06-25 16:58
/**
把日期转换成yyyymmddhh24miss的字符形式.
**/
String zdate_str=sundate+suntime;
if(!isDate(zdate_str)) {
inputfile.close();
readfile.close();
System.out.println("非法文件, 被删除!");
arry.delete();
continue;
}
/**
存储一个数据库SQL语句的日期类型.
**/
String date_value="to_date('"+zdate_str+"','yyyymmddhh24miss')";
readfile.read(title_total,0,4);


/**
存储新闻标题的长度知.
**/
int title_total_i=toInt(title_total);
readfile.read(news_title,0,title_total_i);
/**
新闻标题
**/
String news_title_value=new String(news_title,0,title_total_i);
news_title_value=news_title_value.replace('\'',''');

/**
新闻内容的长度.
**/

int news_content_int=0;
while(readfile.read(temp,0,1)!=-1){
news_content[news_content_int++]=temp[0];
}
/**
新闻内容.
**/
// String news_content_value=new String(news_content,0,news_content_int-1);
String news_content_value = new String(news_content).trim();

/**
插入数据库的SQL语句.
**/
String insert_info_content ="insert into t_news_content_1(news_id,news_time,news_release,news_title,news_content) values("+news_id+","+date_value+","+1+",'"+news_title_value+"',empty_clob())";
System.out.println("insert_info_content:"+insert_info_content);
// String insert_info_content1 ="insert into t_news_content_1_all(news_id,news_time,news_release,news_title,news_content) values("+news_id+","+date_value+","+1+",'"+news_title_value+"',empty_clob())";
stmt = conn.createStatement ();
stmt.execute(insert_info_content);
// stmt.execute(insert_info_content1);
/**
用如查询ORACLE数据库的CLOB字段的结果集.
**/
OracleResultSet ors = (OracleResultSet)stmt.executeQuery("select news_content from t_news_content_1 where news_id ="+news_id+" for update");
if(ors.next())
{
/**
新闻内容的CLOB值.
**/
CLOB clob = ors.getCLOB(1);
clob.putString(1,news_content_value);
System.out.println("news_content_value:"+news_content_value);
}else{
this.stop();this.destroy();
}
/* ors = (OracleResultSet)stmt.executeQuery("select news_content from t_news_content_1_all where news_id ="+news_id+" for update");
if(ors.next())
{

// 新闻内容的CLOB值.

CLOB clob = ors.getCLOB(1);
clob.putString(1,news_content_value);
}else{
this.stop();this.destroy();
} */
System.out.print("插入成功..... ");
ors=null;
// rd.close();
inputfile.close();
readfile.close();
//ostmt.close();
conn.close();
stmt.close();
result.close();
System.out.println(arry.getName()+"被删除");
arry.delete();
}

sernews.insertthread();
this.stop();
this.destroy();
}
catch(IOException e)
{
System.out.println(e);
arry[delete_i].delete();
sernews.insertthread();
this.stop();
this.destroy();
}

catch(SQLException e)
{
try{
this.sleep(6000);
}catch(Exception ex){}
System.out.println("数据库中断......");
sernews.insertthread();
this.stop();
this.destroy();
}
catch(Exception e)
{ System.out.println("有异常发生,忽略.....");
sernews.insertthread();
this.stop();
this.destroy();
}




}

这个是通过一个多线程的形式读入的,
但是遇到一个问题,就是在读入一个文件的时候,放在缓存里了。
写入数据库,当读第二个文件时,不知道为什么,第一个文件的缓存没有清理干净。导致在写第二个文件的时候,第一个还有一部分也写入到第二个文件的下边了。
这个问题是对于读3k的文件就不行。不知道什么原因,还请大家帮我看看 。谢谢,在线等。

banq
2007-06-25 18:05
>是在读入一个文件的时候,放在缓存里了。
>写入数据库,当读第二个文件时,不知道为什么,第一个文件的缓存没有清理干净。>导致在写第二个文件的时候,第一个还有一部分也写入到第二个文件的下边了。
两个线程分享一个缓存,当然会冲突了。

两个解决方向:
1. 同步锁定缓存,某个时刻只能有一个线程访问读取,读取完清空。
2. 每个线程每个缓存,可以使用threadlocal试看。

computerboy
2007-06-26 09:21
banq 大哥能给一个具体方面的实现么,
我对线程这块不是那么熟悉的。
还望大家帮忙一下,谢谢