多线程并发思考--文件加锁
在最近的工作中,经常要用到线程,就对线程相关知识稍微看了看,知道并发线程经常引起共享资源冲突,java以提供关键字synchronized的形式,为防止资源冲突提供了内置支持.
可是在工作中,我却碰到了这样的需求,定时抛出线程读写某文件的内容,由于相隔时间很短,我突然想到,会不会在第二次轮循开始对该文件进行读操作的时候,第一次抛出的线程还在对该文件进行写操作,如果有可能,那么第二次读出的数据会是什么样的呢?
怀着这样的疑问,我开始以程序作实验,代码如下:
1.用于写文件的线程
packagechb.thread;
importjava.io.BufferedWriter;
importjava.io.File;
importjava.io.FileWriter;
importjava.io.IOException;
importjava.util.Calendar;
/**
*@author崔红保
*
*这个线程用于写文件
*/
publicclassThread_writeFileextendsThread{
publicvoidrun(){
Calendarcalstart=Calendar.getInstance();
Filefile=newFile("D:/test.txt");
try{
if(!file.exists())
file.createNewFile();
FileWriterfw=newFileWriter(file);
BufferedWriterbw=newBufferedWriter(fw);
for(inti=0;i<1000;i++){
sleep(10);
bw.write("这是第"+(i+1)+"行,应该没错哈
");
}
bw.close();
bw=null;
fw.close();
fw=null;
}catch(IOExceptione){
e.printStackTrace();
}catch(InterruptedExceptione){
e.printStackTrace();
}
Calendarcalend=Calendar.getInstance();
System.out.println("写文件共用了"+(calend.getTimeInMillis()-calstart.getTimeInMillis())+"毫秒");
}
}
2.用于读文件的线程
packagechb.thread;
importjava.io.BufferedReader;
importjava.io.File;
importjava.io.FileNotFoundException;
importjava.io.FileReader;
importjava.io.IOException;
importjava.util.Calendar;
/**
*@author崔红保
*
*这个线程用于读文件
*/
publicclassThread_readFileextendsThread{
publicvoidrun(){
try{
Calendarcalstart=Calendar.getInstance();
sleep(5000);
Filefile=newFile("D:/test.txt");
BufferedReaderbr=newBufferedReader(newFileReader(file));
Stringtemp=null;
temp=br.readLine();
while(temp!=null){
System.out.println(temp);
temp=br.readLine();
}
br.close();
br=null;
Calendarcalend=Calendar.getInstance();
System.out.println("读文件共用了"+(calend.getTimeInMillis()-calstart.getTimeInMillis())+"毫秒");
}catch(FileNotFoundExceptione){
e.printStackTrace();
}catch(IOExceptione){
e.printStackTrace();
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
}
3.分别启用两个线程
Thread_writeFilethf3=newThread_writeFile();
Thread_readFilethf4=newThread_readFile();
thf3.start();
thf4.start();
4.结果分析
虽然写文件的操作开始5秒钟后,读文件的操作才开始进行,可是读文件的线程并没有读出数据,改变时间,读出的数据也就各不相同.
为了避免以上结果,我们希望在一个线程在操作某个文件的时候,其他线程不能对该文件进行读或写操作,要怎么才能实现呢?利用java提供的synchronized似乎无法完成,因为每个线程是在程序中动态抛出的.郁昧了一天之后,我终于找到了一个解决办法,就是利用java.nio包中的FileChannel对文件进行加锁.
具体实现方法如下:
1.写文件的线程
packagechb.thread;
importjava.io.File;
importjava.io.FileOutputStream;
importjava.io.IOException;
importjava.nio.channels.FileChannel;
importjava.nio.channels.FileLock;
importjava.util.Calendar;
/**
*@authorchb
*
*/
publicclassThread_writeFileextendsThread{
publicvoidrun(){
Calendarcalstart=Calendar.getInstance();
Filefile=newFile("D:/test.txt");
try{
if(!file.exists())
file.createNewFile();
//对该文件加锁
FileOutputStreamout=newFileOutputStream(file,true);
FileChannelfcout=out.getChannel();
FileLockflout=null;
while(true){
flout=fcout.tryLock();
if(flout!=null){
break;
}
else{
System.out.println("有其他线程正在操作该文件,当前线程休眠1000毫秒");
sleep(100);
}
}
for(inti=1;i<=1000;i++){
sleep(10);
StringBuffersb=newStringBuffer();
sb.append("这是第"+i+"行,应该没啥错哈
");
out.write(sb.toString().getBytes("utf-8"));
}
flout.release();
fcout.close();
out.close();
out=null;
}catch(IOExceptione){
e.printStackTrace();
}catch(InterruptedExceptione){
e.printStackTrace();
}
Calendarcalend=Calendar.getInstance();
System.out.println("写文件共花了"+(calend.getTimeInMillis()-calstart.getTimeInMillis())+"秒");
}
}
2.读文件的线程
packagechb.thread;
importjava.io.File;
importjava.io.FileInputStream;
importjava.io.FileNotFoundException;
importjava.io.IOException;
importjava.nio.channels.FileChannel;
importjava.nio.channels.FileLock;
importjava.util.Calendar;
/**
*@authorchb
*���ļ�
*/
publicclassThread_readFileextendsThread{
publicvoidrun(){
try{
Calendarcalstart=Calendar.getInstance();
sleep(5000);
Filefile=newFile("D:/test.txt");
//给该文件加锁
FileInputStreamfis=newFileInputStream(file);
FileChannelfcin=fis.getChannel();
FileLockflin=null;
while(true){
flin=fcin.tryLock(0,Long.MAX_VALUE,true);
if(flin!=null){
break;
}
else{
System.out.println("有其他线程正在操作该文件,当前线程休眠1000毫秒");
sleep(1000);
}
}
byte[]buf=newbyte[1024];
StringBuffersb=newStringBuffer();
while((fis.read(buf))!=-1){
sb.append(newString(buf,"utf-8"));
buf=newbyte[1024];
}
System.out.println(sb.toString());
flin.release();
fcin.close();
fis.close();
fis=null;
Calendarcalend=Calendar.getInstance();
System.out.println("读文件共花了"+(calend.getTimeInMillis()-calstart.getTimeInMillis())+"秒");
}catch(FileNotFoundExceptione){
e.printStackTrace();
}catch(IOExceptione){
e.printStackTrace();
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
}
3.分别启用两个线程
Thread_writeFilethf3=newThread_writeFile();
Thread_readFilethf4=newThread_readFile();
thf3.start();
thf4.start();
4.结果分析
以上程序在对一个文件执行写操作前,先对该文件加锁,这样其他线程就不能再对该文件操作,等该线程的写操作结束,释放资源,其他线程才可以继续对该文件执行相应的读写操作.
可是,郁昧的是,这段程序在windows下可以正确执行,在linux下却无效.根据<Thinking in Java>上的观点是:对独占锁或者共享锁的支持必须由底层的操作系统提供.
综观我的解决方法,总感觉不太完美,各位如有好的方法来判断一个文件是否正被某个线程使用,希望大家一起分享一下.
多线程并发思考--文件加锁
在最近的工作中,经常要用到线程,就对线程相关知识稍微看了看,知道并发线程经常引起共享资源冲突,java以提供关键字synchronized的形式,为防止资源冲突提供了内置支持.
可是在工作中,我却碰到了这样的需求,定时抛出线程读写某文件的内容,由于相隔时间很短,我突然想到,会不会在第二次轮循开始对该文件进行读操作的时候,第一次抛出的线程还在对该文件进行写操作,如果有可能,那么第二次读出的数据会是什么样的呢?
怀着这样的疑问,我开始以程序作实验,代码如下:
1.用于写文件的线程
packagechb.thread;
importjava.io.BufferedWriter;
importjava.io.File;
importjava.io.FileWriter;
importjava.io.IOException;
importjava.util.Calendar;
/**
*@author崔红保
*
*这个线程用于写文件
*/
publicclassThread_writeFileextendsThread{
publicvoidrun(){
Calendarcalstart=Calendar.getInstance();
Filefile=newFile("D:/test.txt");
try{
if(!file.exists())
file.createNewFile();
FileWriterfw=newFileWriter(file);
BufferedWriterbw=newBufferedWriter(fw);
for(inti=0;i<1000;i++){
sleep(10);
bw.write("这是第"+(i+1)+"行,应该没错哈
");
}
bw.close();
bw=null;
fw.close();
fw=null;
}catch(IOExceptione){
e.printStackTrace();
}catch(InterruptedExceptione){
e.printStackTrace();
}
Calendarcalend=Calendar.getInstance();
System.out.println("写文件共用了"+(calend.getTimeInMillis()-calstart.getTimeInMillis())+"毫秒");
}
}
2.用于读文件的线程
packagechb.thread;
importjava.io.BufferedReader;
importjava.io.File;
importjava.io.FileNotFoundException;
importjava.io.FileReader;
importjava.io.IOException;
importjava.util.Calendar;
/**
*@author崔红保
*
*这个线程用于读文件
*/
publicclassThread_readFileextendsThread{
publicvoidrun(){
try{
Calendarcalstart=Calendar.getInstance();
sleep(5000);
Filefile=newFile("D:/test.txt");
BufferedReaderbr=newBufferedReader(newFileReader(file));
Stringtemp=null;
temp=br.readLine();
while(temp!=null){
System.out.println(temp);
temp=br.readLine();
}
br.close();
br=null;
Calendarcalend=Calendar.getInstance();
System.out.println("读文件共用了"+(calend.getTimeInMillis()-calstart.getTimeInMillis())+"毫秒");
}catch(FileNotFoundExceptione){
e.printStackTrace();
}catch(IOExceptione){
e.printStackTrace();
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
}
3.分别启用两个线程
Thread_writeFilethf3=newThread_writeFile();
Thread_readFilethf4=newThread_readFile();
thf3.start();
thf4.start();
4.结果分析
虽然写文件的操作开始5秒钟后,读文件的操作才开始进行,可是读文件的线程并没有读出数据,改变时间,读出的数据也就各不相同.
为了避免以上结果,我们希望在一个线程在操作某个文件的时候,其他线程不能对该文件进行读或写操作,要怎么才能实现呢?利用java提供的synchronized似乎无法完成,因为每个线程是在程序中动态抛出的.郁昧了一天之后,我终于找到了一个解决办法,就是利用java.nio包中的FileChannel对文件进行加锁.
具体实现方法如下:
1.写文件的线程
packagechb.thread;
importjava.io.File;
importjava.io.FileOutputStream;
importjava.io.IOException;
importjava.nio.channels.FileChannel;
importjava.nio.channels.FileLock;
importjava.util.Calendar;
/**
*@authorchb
*
*/
publicclassThread_writeFileextendsThread{
publicvoidrun(){
Calendarcalstart=Calendar.getInstance();
Filefile=newFile("D:/test.txt");
try{
if(!file.exists())
file.createNewFile();
//对该文件加锁
FileOutputStreamout=newFileOutputStream(file,true);
FileChannelfcout=out.getChannel();
FileLockflout=null;
while(true){
flout=fcout.tryLock();
if(flout!=null){
break;
}
else{
System.out.println("有其他线程正在操作该文件,当前线程休眠1000毫秒");
sleep(100);
}
}
for(inti=1;i<=1000;i++){
sleep(10);
StringBuffersb=newStringBuffer();
sb.append("这是第"+i+"行,应该没啥错哈
");
out.write(sb.toString().getBytes("utf-8"));
}
flout.release();
fcout.close();
out.close();
out=null;
}catch(IOExceptione){
e.printStackTrace();
}catch(InterruptedExceptione){
e.printStackTrace();
}
Calendarcalend=Calendar.getInstance();
System.out.println("写文件共花了"+(calend.getTimeInMillis()-calstart.getTimeInMillis())+"秒");
}
}
2.读文件的线程
packagechb.thread;
importjava.io.File;
importjava.io.FileInputStream;
importjava.io.FileNotFoundException;
importjava.io.IOException;
importjava.nio.channels.FileChannel;
importjava.nio.channels.FileLock;
importjava.util.Calendar;
/**
*@authorchb
*���ļ�
*/
publicclassThread_readFileextendsThread{
publicvoidrun(){
try{
Calendarcalstart=Calendar.getInstance();
sleep(5000);
Filefile=newFile("D:/test.txt");
//给该文件加锁
FileInputStreamfis=newFileInputStream(file);
FileChannelfcin=fis.getChannel();
FileLockflin=null;
while(true){
flin=fcin.tryLock(0,Long.MAX_VALUE,true);
if(flin!=null){
break;
}
else{
System.out.println("有其他线程正在操作该文件,当前线程休眠1000毫秒");
sleep(1000);
}
}
byte[]buf=newbyte[1024];
StringBuffersb=newStringBuffer();
while((fis.read(buf))!=-1){
sb.append(newString(buf,"utf-8"));
buf=newbyte[1024];
}
System.out.println(sb.toString());
flin.release();
fcin.close();
fis.close();
fis=null;
Calendarcalend=Calendar.getInstance();
System.out.println("读文件共花了"+(calend.getTimeInMillis()-calstart.getTimeInMillis())+"秒");
}catch(FileNotFoundExceptione){
e.printStackTrace();
}catch(IOExceptione){
e.printStackTrace();
}catch(InterruptedExceptione){
e.printStackTrace();
}
}
}
3.分别启用两个线程
Thread_writeFilethf3=newThread_writeFile();
Thread_readFilethf4=newThread_readFile();
thf3.start();
thf4.start();
4.结果分析
以上程序在对一个文件执行写操作前,先对该文件加锁,这样其他线程就不能再对该文件操作,等该线程的写操作结束,释放资源,其他线程才可以继续对该文件执行相应的读写操作.
可是,郁昧的是,这段程序在windows下可以正确执行,在linux下却无效.根据<Thinking in Java>上的观点是:对独占锁或者共享锁的支持必须由底层的操作系统提供.
综观我的解决方法,总感觉不太完美,各位如有好的方法来判断一个文件是否正被某个线程使用,希望大家一起分享一下.
分享到:
相关推荐
vc++ 多线程教程---线程通信--利用事件对象,线程同步--使用信号量,线程同步--使用互斥量,线程同步--使用临界区
多线程并发编程-同步与互斥-原⼦变量-并发和⽆锁 数据结构
Tesseract OCR多线程并发识别案例----只演示多线程并发识别,此工具不关注识别正确率,可通过训练tessdata来获得更高的识别正确率。
并发服务器-多线程服务器详解
多线程精品资源--高并发-高可靠-高性能three-high-import导入系统-高并发多线程进阶
Java多线程与线程安全实践-基于Http协议的断点续传 Java多线程与线程安全实践-基于Http协议的断点续传 Java多线程与线程安全实践-基于Http协议的断点续传 Java多线程与线程安全实践-基于Http协议的断点...Java多线程与
JAVA多线程与线程安全实践-基于Http协议的断点续传 JAVA多线程与线程安全实践-基于Http协议的断点续传 JAVA多线程与线程安全实践-基于Http协议的断点续传 JAVA多线程与线程安全实践-基于Http协议的断点续传 JAVA多...
Java多线程与线程安全实践-基于Http协议的断点续传.rarJava多线程与线程安全实践-基于Http协议的断点续传.rarJava多线程与线程安全实践-基于Http协议的断点续传.rarJava多线程与线程安全实践-基于Http协议的断点续传...
Java 多线程与并发-Java并发知识体系详解
多线程精品资源--多线程与高并发
基于Java多线程与线程安全实践-基于Http协议的断点续传设计与实现.zip基于Java多线程与线程安全实践-基于Http协议的断点续传设计与实现.zip基于Java多线程与线程安全实践-基于Http协议的断点续传设计与实现.zip基于...
马士兵老师课程笔记 https://www.bilibili.com/video/BV1of4y1p74A?p=45
基于Qt的多线程并发服务器 incomingConnection(qintptr socketDescriptor)检测
linux下的多线程实例--生产者消费者 linux下的多线程实例--生产者消费者
Java多线程实战精讲-带你一次搞明白Java多线程高并发
易语言源码多文件多线程传送--.7z
操作系统--多线程买票---python--有窗体界面,就是操作系统课上的一个课外练习,传上去,保存下来。 exe文件在 map文件夹-->dict文件夹-->map文件夹-->map.exe 已经打包好了,没有python环境的电脑上也...
Java 模拟线程并发 Java, 模拟线程并发,线程,并发 Java, 模拟线程并发,线程,并发 Java, 模拟线程并发,线程,并发 Java, 模拟线程并发,线程,并发
本书主要讲述采用现代C++ 在x86-64 Linux 上编写多线程TCP 网络服务程序的主流常规技术,重点讲解一种适应性较强的多线程服务器的编程模型,即one loop per thread。这是在Linux 下以native 语言编写用户态高性能...