多线程并发思考--文件加锁

多线程并发思考--文件加锁

         在最近的工作中,经常要用到线程,就对线程相关知识稍微看了看,知道并发线程经常引起共享资源冲突,java以提供关键字synchronized的形式,为防止资源冲突提供了内置支持.

         可是在工作中,我却碰到了这样的需求,定时抛出线程读写某文件的内容,由于相隔时间很短,我突然想到,会不会在第二次轮循开始对该文件进行读操作的时候,第一次抛出的线程还在对该文件进行写操作,如果有可能,那么第二次读出的数据会是什么样的呢?

        怀着这样的疑问,我开始以程序作实验,代码如下:

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)+"行,应该没错哈 ");
            }

            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.结果分析

虽然写文件的操作开始5秒钟后,读文件的操作才开始进行,可是读文件的线程并没有读出数据,改变时间,读出的数据也就各不相同.

         为了避免以上结果,我们希望在一个线程在操作某个文件的时候,其他线程不能对该文件进行读或写操作,要怎么才能实现呢?利用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下却无效.根据上的观点是:对独占锁或者共享锁的支持必须由底层的操作系统提供.

          综观我的解决方法,总感觉不太完美,各位如有好的方法来判断一个文件是否正被某个线程使用,希望大家一起分享一下.

你可能感兴趣的:(JAVA)