有一个data.xml文件,提供给网络用户读取使用.每一个用户每5秒钟就要读取一次.
在服务端,有一个程序每过几秒就将一些数据写入这个文件.(完全重新写入,不是追加)我现在遇到一个问题,当用户访问频率太高,写入动作就会有问题.有时写入后文件大小为0.现在程序已经上线运行,看不出问题在哪.测试环境下很难达到那样的访问频率,也不好测试.各位谁遇到过这样的情况给个解决思路也欢迎大家来讨论一下
在服务端,有一个程序每过几秒就将一些数据写入这个文件.(完全重新写入,不是追加)我现在遇到一个问题,当用户访问频率太高,写入动作就会有问题.有时写入后文件大小为0.现在程序已经上线运行,看不出问题在哪.测试环境下很难达到那样的访问频率,也不好测试.各位谁遇到过这样的情况给个解决思路也欢迎大家来讨论一下
写入为大小为0,就是读取的时候发现那个文件是空的,size是0,打开后没有字符。这就是问题。
如果取文件是我自己处理,那当然好办了。还用什么jsp呀,一个servlet就okay了,那也不用写data.xml,直接在内存中处理就可以了
可是java的http容器性能存在问题,用户用的是tomcat,大访问量早趴下了。只能交给iis来处理
所以我才生成xml文件的。这样我就没办法做同步了。
这个是读取数据文件的类
启动时输入100之类的数字,表示读取线程数
再输入读取文件的url,如file:\\\e:\a.txtpackage read;import java.io.*;
import java.net.*;public class FileReaderThread implements Runnable {
static {
lock = new Object();
}
static boolean isDestroy = false;
static long readTime = 0;
static Object lock ;
static String filePath;
static long storedTimes=0;
public FileReaderThread() {
} public void run() {
while (!isDestroy) {
readFile();
synchronized (lock) {
if (readTime %1000 == 0) {
System.out.println("Read times = " + readTime+",store times = "+storedTimes);
}
}
try {
Thread.sleep(100);
} catch (InterruptedException ex) {
}
}
} private void readFile() {
long time=-1;
InputStreamReader isr = null;
long size = 0;
try {
URL url = new URL(filePath);
isr = new InputStreamReader(url.openConnection().getInputStream());
BufferedReader br = new BufferedReader(isr);
String line;
while ((line = br.readLine()) != null) {
if(time<0){
time=Long.parseLong(line.trim());
}
size += line.trim().length();
}
} catch (Exception ex) {
ex.printStackTrace();
return;
} finally {
if (isr != null) {
try {
isr.close();
} catch (Exception ex1) {
}
}
}
if (size <=10) {
System.err.println("Size = "+size);
}
synchronized (lock) {
readTime++;
if(time>storedTimes){
storedTimes=time;
System.out.println("Stored times changed : "+storedTimes);
}
}
} public static void main(String args[]) {
int num = 0;
while (true) {
System.out.println("Input read thread num:");
byte buf[] = new byte[100];
int size = 0;
try {
size = System.in.read(buf);
if (size <= 0) {
continue;
}
String str = new String(buf, 0, size);
num = Integer.parseInt(str.trim());
} catch (Exception ex1) {
}
break ;
}
while (true) {
System.out.println("Input file url:");
byte buf[] = new byte[1024];
int size = 0;
try {
size = System.in.read(buf);
if (size <= 0) {
continue;
}
String str = new String(buf, 0, size).trim();
try {
URL url = new URL(str);
} catch (MalformedURLException ex2) {
System.err.println("Err url !");
continue;
}
FileReaderThread.filePath=str;
} catch (Exception ex1) {
}
break ;
}
for (int i = 0; i < num; i++) {
new Thread(new FileReaderThread()).start();
} while (true) {
try {
byte buf[] = new byte[100];
int size = System.in.read(buf);
if (size <= 0) {
continue;
}
String str = new String(buf, 0, size);
if (str.equalsIgnoreCase("exit")) {
FileReaderThread.isDestroy = true;
return;
}
} catch (IOException ex) {
}
}
}
}
下面是写文件类
启动时输入写入类型,1是直接写入,2是写入零时文件后拷贝过来package write;import java.io.*;public class FileWriteThread implements Runnable {
static boolean isDestroy = false;
static int type;
private long times = 0;
public FileWriteThread() {
} public void run() {
while (!isDestroy) {
try {
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
switch (type) {
case 1:
writeFile1();
break;
case 2:
writeFile2();
break;
default:
System.out.println("Err write type");
}
System.out.println("Write times = " + times);
}
} private void writeFile1() {
File f = new File("a.txt");
BufferedWriter bw = null;
FileWriter fw = null;
try {
fw = new FileWriter(f);
bw = new BufferedWriter(fw);
bw.write(""+times);
bw.newLine();
bw.flush();
for (int i = 0; i < 1000; i++) {
bw.write("index="+times);
bw.newLine();
bw.flush();
}
} catch (Exception ex) {
} finally {
if (fw != null) {
try {
fw.close();
} catch (IOException ex1) {
}
}
}
times++;
}
private void writeFile2() {
File f = null;
try {
f = File.createTempFile("tempwritefile", "temp");
} catch (Exception ex2) {
ex2.printStackTrace();
return;
}
BufferedWriter bw = null;
FileWriter fw = null;
try {
fw = new FileWriter(f);
bw = new BufferedWriter(fw);
bw.write(""+times);
bw.newLine();
bw.flush();
for (int i = 0; i < 1000; i++) {
bw.write("index="+times);
bw.newLine();
bw.flush();
}
} catch (Exception ex) {
} finally {
if (fw != null) {
try {
fw.close();
} catch (IOException ex1) {
}
}
}
File df=new File("a.txt");
df.delete();
f.renameTo(df);
f.delete();
times++;
}
public static void main(String args[]) {
int type = 0;
while (true) {
System.out.println("Input write type :");
byte buf[] = new byte[100];
int size = 0;
try {
size = System.in.read(buf);
if (size <= 0) {
continue;
}
String str = new String(buf, 0, size);
type = Integer.parseInt(str.trim());
if(type>3|| type<1){
System.out.println("Type should be 1,2,3");
continue;
}
FileWriteThread.type=type;
} catch (Exception ex1) {
}
break ;
}
new Thread(new FileWriteThread()).start();
while (true) {
try {
byte buf[] = new byte[100];
int size = System.in.read(buf);
if (size <= 0) {
continue;
}
String str = new String(buf, 0, size);
if (str.equalsIgnoreCase("exit")) {
FileWriteThread.isDestroy = true;
return;
}
} catch (Exception ex) {
}
}
}
}运行后看看,会发现
如果选择直接写入,读取时会出现size=0的情况,如果read线程很多,这种现象越明显
如果采用拷贝的方法,读取时会出现很长时间读取的都是同一个文件对于io操作的互斥和饿死现象我就不多说了
只是这样的需求怎么实现呢?我这个data.xml是要给网页提供数据的,数据间隔大约就是3秒。本以为很简单的东西,怎么还碰了壁了呢
至少新手也可以从这里学习一下文件操作和url操作呀帮忙顶一下啊
就是用File.nameTo方法将新生成的文件改名为目标文件,(可能由于目标文件在被使用,结果改名失败)目标文件很可能没有被替换,结果客户读取的数据都是原来的旧数据。
如果选择直接写入,读取时会出现size=0的情况,如果read线程很多,这种现象越明显
如果采用拷贝的方法,读取时会出现很长时间读取的都是同一个文件关于这个问题,MS你采用的是时间片轮转的方法,可能是在时间片用完的时候,数据还没有从缓冲池中写入文件 ,造成文件为空。试试时间片稍微大一点? 采用拷贝的话,是不是缓冲池中间没有清空? (乱说的,不要在意)对于io操作的互斥和饿死现象我就不多说了
互斥 应该实现了,饿死我认为不会出现呀,轮转本身就是一种抢占式调度算法,会出现饿死状况?只是这样的需求怎么实现呢?
拷贝我感觉不是缓冲的问题.很可能是原文件正在被read,这是新文件要拷贝到原文件上可能出现失败.这样就可能出现拷贝不成功,而读取的都是相同内容真正的饿死是不会出现,但读取太频繁,造成文件实际上一直处于被读取状态,那写入线程实际上很难得到文件的操作权.现象上类似于饿死现在的问题是怎么实现我这样的需求呢?