各位大虾好: 现有一功能,涉及到对一文件进行并发读写操作,未避免并发问题,想到的办法是调用读写方法前新建一个锁文件,方法执行完后删除锁文件。
 现在想要测试文件并发功能,但读写时报错,对于这块不够了解,希望各位能给予指教。
如果有文件并发读写的示例和测试代码,也希望能贴出。
并发测试文件读写

解决方案 »

  1.   

    文件读定,如果你是在同一个JVM里面的话你直接同步读定代码不就可以了吗?如果是不同JVM的话,我的建议是你其实不用建立一个锁文件只需要在读文件时复制一份出来,读的线程去读这个copy就行了.写文件的线程只需要写不需要同步了.这样每一个读写线程都有自己的一份专用文件来操作了.当然写线程只能有一个.
      

  2.   

    看看,不符合要求,自己再改改吧~
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.File;
    import java.io.FileInputStream;
    import java.io.FileNotFoundException;
    import java.io.FileOutputStream;
    import java.io.IOException;
    import java.io.InputStreamReader;
    import java.io.OutputStreamWriter;
    import java.nio.channels.FileLock;
    public class ReadAndWriteByLock
    {    public static void main(String[] args)
        {
            Runnable readThread = new Runnable()
            {            public void run()
                {
                    File oneFile = new File("allMyWords.txt");
                    readFileByLock(oneFile);
                }
            };        Runnable writeThread = new Runnable()
            {            public void run()
                {
                    File oneFile = new File("allMyWords.txt");
                    writeFileByLock(oneFile, "番茄鸡蛋我最爱!");
                }
            };        //异步线程测试
            new Thread(writeThread).start();
            new Thread(readThread).start();
        }    /**
         * 读成功返回成功
         * @param file  待操作的文件
         * @return
         */
        private static boolean readFileByLock(File file)
        {
            BufferedReader br = null;
            try
            {
                //读操作不需要加锁
                br = new BufferedReader(new InputStreamReader(new FileInputStream(file)));            //对文件的读操作
                String strTmp;
                while ((strTmp = br.readLine()) != null)
                {
                    System.out.println("文件读取成功:" + strTmp);
                }
            }
            catch (FileNotFoundException e)
            {
                //文件不存在,返回失败
                e.printStackTrace();
                return false;
            }
            catch (IOException e)
            {
                //不可控的其它异常
                e.printStackTrace();
                return false;
            }
            finally
            {
                if (null != br)
                {
                    try
                    {
                        br.close();
                    }
                    catch (IOException e)
                    {
                        //关闭资源失败,返回失败
                        e.printStackTrace();
                        return false;
                    }
                }
            }        return true;
        }    /**
         * 写成功返回成功
         * @param file  待操作的文件
         * @param myWords 追加的字符串
         * @return
         */
        private static boolean writeFileByLock(File file, String myWords)
        {
            BufferedWriter bw = null;
            FileLock lock = null;
            FileOutputStream fos = null;
            try
            {
                //写操作需要锁文件
                fos = new FileOutputStream(file, true);//true表示追加
                int counter = 0;
                try
                {
                    lock = fos.getChannel().tryLock();
                }
                catch (IOException e)
                {
                    e.printStackTrace();
                }
                //若锁失败,循环三次
                while (lock == null)
                {
                    counter++;
                    //若超过3次,直接返回失败
                    if (counter > 3)
                    {
                        return false;
                    }                try
                    {
                        //等3秒后加锁
                        Thread.sleep(3000);
                    }
                    catch (InterruptedException e1)
                    {
                        e1.printStackTrace();
                    }
                    try
                    {
                        lock = fos.getChannel().tryLock();
                    }
                    catch (IOException e)
                    {
                        e.printStackTrace();
                    }
                }            bw = new BufferedWriter(new OutputStreamWriter(fos));            //对文件的写操作
                bw.write(myWords);
                bw.newLine();
                System.out.println("文件写入成功!");
            }
            catch (FileNotFoundException e)
            {
                //文件不存在,返回失败
                e.printStackTrace();
                return false;
            }
            catch (IOException e)
            {
                //不可控的其它异常
                e.printStackTrace();
                return false;
            }
            finally
            {
                if (null != lock)
                {
                    try
                    {
                        lock.release();
                    }
                    catch (IOException e)
                    {
                        //释放锁失败,返回失败
                        e.printStackTrace();
                        return false;
                    }
                }            if (null != bw)
                {
                    try
                    {
                        bw.close();
                    }
                    catch (IOException e)
                    {
                        //关闭资源失败,返回失败
                        e.printStackTrace();
                        return false;
                    }
                }
            }
            return true;
        }
    }
      

  3.   

    非常感谢。
    另外请教两个问题:
    1、请问为什么读不需要锁呢?
    2、问什么只需要对文件加锁?假设一个action 调用 service 方法,service方法包含了对文件的读写。
    那我如果只对文件加了锁,能保证读出来的内容是同步的正确的,但是,service里的内容会是正确的么?
    就是说,
    一个action:Action
    一个service:Service
    Action是多线程,那Action里调用Service里方法,是创建了两块不同内存区域存储Service方法里的对象,只有当文件读写时,这两块区域才会可能有并发的交集。所以只需要对文件进行加锁,请问我理解对么?
      

  4.   

    非常感谢。
    另外请教两个问题:
    1、请问为什么读不需要锁呢?
    2、问什么只需要对文件加锁?假设一个action 调用 service 方法,service方法包含了对文件的读写。
    那我如果只对文件加了锁,能保证读出来的内容是同步的正确的,但是,service里的内容会是正确的么?
    就是说,
    一个action:Action
    一个service:Service
    Action是多线程,那Action里调用Service里方法,是创建了两块不同内存区域存储Service方法里的对象,只有当文件读写时,这两块区域才会可能有并发的交集。所以只需要对文件进行加锁,请问我理解对么?
      

  5.   

    非常感谢。
    另外请教两个问题:
    1、请问为什么读不需要锁呢?
    2、问什么只需要对文件加锁?假设一个action 调用 service 方法,service方法包含了对文件的读写。
    那我如果只对文件加了锁,能保证读出来的内容是同步的正确的,但是,service里的内容会是正确的么?
    就是说,
    一个action:Action
    一个service:Service
    Action是多线程,那Action里调用Service里方法,是创建了两块不同内存区域存储Service方法里的对象,只有当文件读写时,这两块区域才会可能有并发的交集。所以只需要对文件进行加锁,请问我理解对么?
    读不需要加锁,是因为就算文件锁住了,也是可以读的,只是有可能读的数据不是最终的数据。
    如果要求读的也是正确的,最好再加一个标志(如static int flag=0,未锁)标记文件是否被锁了。任意线程读或写文件之前,先判断flag(synchronized方法判断此标志位),为0,就先将其改为1,然后操作文件,操作完了改为0;为1,则等待。(LZ可以把我的lock换成flag试试)
      

  6.   

    以下是多线程读写操作文件的一个例子,如果你觉得线程太多调试麻烦,可以将线程数改小一点就可以了。
    import java.io.BufferedReader;
    import java.io.BufferedWriter;
    import java.io.File;
    import java.io.FileNotFoundException;
    import java.io.FileReader;
    import java.io.FileWriter;
    import java.io.IOException;
    import java.util.ArrayList;
    import java.util.List;
    import java.util.concurrent.ThreadFactory;
    import java.util.concurrent.atomic.AtomicInteger;
    import java.util.concurrent.locks.ReentrantReadWriteLock;
    import java.util.concurrent.locks.ReentrantReadWriteLock.ReadLock;
    import java.util.concurrent.locks.ReentrantReadWriteLock.WriteLock;public class ReadWriteFileThread {
        private static final int READ_WIRTE_LOOP_COUNT = 10;    private static final ReentrantReadWriteLock locker = new ReentrantReadWriteLock(
                false);
        private static final WriteLock writeLocker = locker.writeLock();
        private static final ReadLock readLock = locker.readLock();
        private static final AtomicInteger threadIndex = new AtomicInteger(1);    private static final int READ_THREAD_NUMBER = 5;
        private static final int WRITE_THREAD_NUMBER = 5;    private static final List<Thread> readThreads = new ArrayList<Thread>(
                READ_THREAD_NUMBER);
        private static final List<Thread> writeThreads = new ArrayList<Thread>(
                WRITE_THREAD_NUMBER);    /** the specified file **/
        private static final File f = new File("c:\\aa.txt");    /** the read runnable worker **/
        private static final Runnable r = new ReadRunnable(f);    /** the write runnable worker **/
        private static final Runnable w = new WriteRunnable(f);    /**
         * ThreadFactory is used for create the specified thread
         */
        private static final ThreadFactory tf = new ThreadFactory() {
            /**
             * create new thread instance
             */
            public Thread newThread(Runnable r) {
                final Thread t = new Thread(r);            if (r instanceof ReadRunnable) {
                    t.setName("readThread" + threadIndex.getAndIncrement());
                    readThreads.add(t);
                } else if (r instanceof WriteRunnable) {
                    t.setName("writeThread" + threadIndex.getAndIncrement());
                    writeThreads.add(t);
                } else {
                    throw new RuntimeException("the Runnable is not support..");
                }
                t.setDaemon(false);
                return t;
            }
        };    public static void main(String[] args) {
            // create read thread
            for (int i = 0; i < READ_THREAD_NUMBER; i++) {
                tf.newThread(r);
            }        // create write thread
            for (int i = 0; i < WRITE_THREAD_NUMBER; i++) {
                tf.newThread(w);
            }        // start the following threads
            for (final Thread t : readThreads) {
                t.start();
            }        for (final Thread t : writeThreads) {
                t.start();
            }    }    /**
         * ReadRunnable for read from file <br>
         * once a read thread is reached, the other read can be access
         * successfully..<br>
         * but the write thread will be blocked until all read thread is done <br>
         * 
         * @see {@link ReentrantReadWriteLock }
         * @see {@link ReadLock}
         * 
         * @author Administrator
         * 
         */
        static class ReadRunnable implements Runnable {
            private final File file;        public ReadRunnable(final File file) {
                this.file = file;
            }        public void run() {
                final Thread t = Thread.currentThread();
                int loop = 0;
                while (loop++ < READ_WIRTE_LOOP_COUNT) {
                    try {
                        readLock.lock();
                        System.out.println("ready to read from file, thread name:"
                                + t.getName());
                        BufferedReader br = new BufferedReader(new FileReader(file));
                        String line = null;
                        while ((line = br.readLine()) != null) {
                            System.out.println(line);
                        }
                    } catch (FileNotFoundException ex) {
                        System.out.println("the file has not been created yet. "
                                + "need to wait for write thread");
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    } finally {
                        readLock.unlock();
                    }                try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }        }
        }    /**
         * WriteRunnable for write to file <br>
         * once a write thread is reached, the other write can not be access <br>
         * and the read thread also been blocked until the write thread is done <br>
         * 
         * @see {@link ReentrantReadWriteLock }
         * @see {@link WriteLock}
         * 
         * @author Administrator
         * 
         */
        static class WriteRunnable implements Runnable {
            private final File file;        public WriteRunnable(final File file) {
                this.file = file;
            }        public void run() {
                final Thread t = Thread.currentThread();
                int loop = 0;
                while (loop++ < READ_WIRTE_LOOP_COUNT) {
                    try {
                        writeLocker.lock();
                        System.out.println("ready to write to file, thread name:"
                                + t.getName());
                        BufferedWriter br = new BufferedWriter(new FileWriter(file,
                                true));
                        br.write("hello world! wirte thread Name:" + t.getName()
                                + "\r\n");
                        br.flush();
                    } catch (FileNotFoundException ex) {
                        ex.printStackTrace();
                    } catch (IOException ex) {
                        ex.printStackTrace();
                    } finally {
                        writeLocker.unlock();
                    }                try {
                        Thread.sleep(200);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                }
            }
        }
    }
      

  7.   

    非常感谢。
    另外请教两个问题:
    1、请问为什么读不需要锁呢?
    2、问什么只需要对文件加锁?假设一个action 调用 service 方法,service方法包含了对文件的读写。
    那我如果只对文件加了锁,能保证读出来的内容是同步的正确的,但是,service里的内容会是正确的么?
    就是说,
    一个action:Action
    一个service:Service
    Action是多线程,那Action里调用Service里方法,是创建了两块不同内存区域存储Service方法里的对象,只有当文件读写时,这两块区域才会可能有并发的交集。所以只需要对文件进行加锁,请问我理解对么?
    读不需要加锁,是因为就算文件锁住了,也是可以读的,只是有可能读的数据不是最终的数据。
    如果要求读的也是正确的,最好再加一个标志(如static int flag=0,未锁)标记文件是否被锁了。任意线程读或写文件之前,先判断flag(synchronized方法判断此标志位),为0,就先将其改为1,然后操作文件,操作完了改为0;为1,则等待。(LZ可以把我的lock换成flag试试)谢谢oh_Maxy的热心解答。后面我还是采取在读写文件外采用synchronized控制。
    不过这方面还需要进一步理解和深入。