在最近的工作中,經(jīng)常要用到線程,就對線程相關(guān)知識稍微看了看,知道并發(fā)線程經(jīng)常引起共享資源沖突,java以提供關(guān)鍵字synchronized的形式,為防止資源沖突提供了內(nèi)置支持.
可是在工作中,我卻碰到了這樣的需求,定時拋出線程讀寫某文件的內(nèi)容,由于相隔時間很短,我突然想到,會不會在第二次輪循開始對該文件進行讀操作的時候,第一次拋出的線程還在對該文件進行寫操作,如果有可能,那么第二次讀出的數(shù)據(jù)會是什么樣的呢?
懷著這樣的疑問,我開始以程序作實驗,代碼如下:
1.用于寫文件的線程
package chb.thread;import java.io.BufferedWriter;import java.io.File;import java.io.FileWriter;import java.io.IOException;import java.util.Calendar;/** *//*** @author 崔紅保** 這個線程用于寫文件*/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();FileWriter fw=new FileWriter(file);BufferedWriter bw=new BufferedWriter(fw);for(int i=0;i<1000;i++)...{sleep(10);bw.write("這是第"+(i+1)+"行,應(yīng)該沒錯哈 ");}bw.close();bw=null;fw.close();fw=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.BufferedReader;import java.io.File;import java.io.FileNotFoundException;import java.io.FileReader;import java.io.IOException;import java.util.Calendar;/** *//*** @author 崔紅保**這個線程用于讀文件*/public class Thread_readFile extends Thread...{public void run()...{try ...{Calendar calstart=Calendar.getInstance();sleep(5000);File file=new File("D:/test.txt");BufferedReader br=new BufferedReader(new FileReader(file));String temp=null;temp=br.readLine();while(temp!=null)...{System.out.println(temp);temp=br.readLine();}br.close();br=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.結(jié)果分析
雖然寫文件的操作開始5秒鐘后,讀文件的操作才開始進行,可是讀文件的線程并沒有讀出數(shù)據(jù),改變時間,讀出的數(shù)據(jù)也就各不相同.
為了避免以上結(jié)果,我們希望在一個線程在操作某個文件的時候,其他線程不能對該文件進行讀或?qū)懖僮?要怎么才能實現(xiàn)呢?利用java提供的synchronized似乎無法完成,因為每個線程是在程序中動態(tài)拋出的.郁昧了一天之后,我終于找到了一個解決辦法,就是利用java.nio包中的FileChannel對文件進行加鎖.
具體實現(xiàn)方法如下:
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("有其他線程正在操作該文件,當(dāng)前線程休眠1000毫秒");sleep(100);}}for(int i=1;i<=1000;i++)...{sleep(10);StringBuffer sb=new StringBuffer();sb.append("這是第"+i+"行,應(yīng)該沒啥錯哈 ");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("有其他線程正在操作該文件,當(dāng)前線程休眠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.結(jié)果分析
以上程序在對一個文件執(zhí)行寫操作前,先對該文件加鎖,這樣其他線程就不能再對該文件操作,等該線程的寫操作結(jié)束,釋放資源,其他線程才可以繼續(xù)對該文件執(zhí)行相應(yīng)的讀寫操作.
可是,郁昧的是,這段程序在windows下可以正確執(zhí)行,在linux下卻無效.根據(jù)<Thinking in Java>上的觀點是:對獨占鎖或者共享鎖的支持必須由底層的操作系統(tǒng)提供.
綜觀我的解決方法,總感覺不太完美,各位如有好的方法來判斷一個文件是否正被某個線程使用,希望大家一起分享一下.
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1440226