场景:多个地方同时向一个文件读写据,如何保持操作互斥性,即一次只能一个操作(比如读或写)进行。
原文:http://blog.youkuaiyun.com/hbcui1984/archive/2006/12/12/1440226.aspx
我们希望在一个线程在操作某个文件的时候,其他线程不能对该文件进行读或写操作,要怎么才能实现呢?利用java提供的synchronized似乎无法完成,因为每个线程是在程序中动态抛出的.郁昧了一天之后,我终于找到了一个解决办法,就是利用java.nio包中的FileChannel对文件进行加锁.
具体实现方法如下:
1.写文件的线程
package chb.thread;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;import java.nio.channels.FileChannel;import java.nio.channels.FileLock;import java.util.Calendar;/** * @author chb */public class Thread_writeFile extends Thread{ public void run(){ Calendar calstart=Calendar.getInstance(); File file=new File("D:/test.txt"); try { if(!file.exists()) file.createNewFile(); //对该文件加锁 FileOutputStream out=new FileOutputStream(file,true); FileChannel fcout=out.getChannel(); FileLock flout=null; while(true){ flout=fcout.tryLock(); if(flout!=null){ break; } else{ System.out.println("有其他线程正在操作该文件,当前线程休眠1000毫秒"); sleep(100); } } for(int i=1;i<=1000;i++){ sleep(10); StringBuffer sb=new StringBuffer(); sb.append("这是第"+i+"行,应该没啥错哈 "); out.write(sb.toString().getBytes("utf-8")); } flout.release(); fcout.close(); out.close(); out=null; } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } Calendar calend=Calendar.getInstance(); System.out.println("写文件共花了"+(calend.getTimeInMillis()-calstart.getTimeInMillis())+"秒"); }}
2.读文件的线程
package chb.thread;import java.io.File;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;import java.nio.channels.FileChannel;import java.nio.channels.FileLock;import java.util.Calendar;/** * @author chb */public class Thread_readFile extends Thread{ public void run(){ try { Calendar calstart=Calendar.getInstance(); sleep(5000); File file=new File("D:/test.txt"); //给该文件加锁 FileInputStream fis=new FileInputStream(file); FileChannel fcin=fis.getChannel(); FileLock flin=null; while(true){ flin=fcin.tryLock(0,Long.MAX_VALUE,true); if(flin!=null){ break; } else{ System.out.println("有其他线程正在操作该文件,当前线程休眠1000毫秒"); sleep(1000); } } byte[] buf = new byte[1024]; StringBuffer sb=new StringBuffer(); while((fis.read(buf))!=-1){ sb.append(new String(buf,"utf-8")); buf = new byte[1024]; } System.out.println(sb.toString()); flin.release(); fcin.close(); fis.close(); fis=null; Calendar calend=Calendar.getInstance(); System.out.println("读文件共花了"+(calend.getTimeInMillis()-calstart.getTimeInMillis())+"秒"); }catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (InterruptedException e) { e.printStackTrace(); } }}
3.分别启用两个线程
Thread_writeFile thf3=new Thread_writeFile(); Thread_readFile thf4=new Thread_readFile(); thf3.start(); thf4.start();
4.结果分析
以上程序在对一个文件执行写操作前,先对该文件加锁,这样其他线程就不能再对该文件操作,等该线程的写操作结束,释放资源,其他线程才可以继续对该文件执行相应的读写操作.
可是,郁昧的是,这段程序在windows下可以正确执行,在linux下却无效.根据<Thinking in Java>上的观点是:对独占锁或者共享锁的支持必须由底层的操作系统提供。