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

在最近的工作中,经常要用到线程,就对线程相关知识稍微看了看,知道并发线程经常引起共享资源冲突,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下却无效.根据<Thinking in Java>上的观点是:对独占锁或者共享锁的支持必须由底层的操作系统提供.

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

转载于:https://www.cnblogs.com/hehe520/archive/2006/12/12/6330262.html

多线程并发思考--文件加锁相关推荐

  1. C#使用读写锁三行代码简单解决多线程并发写入文件时线程同步的问题

    在开发程序的过程中,难免少不了写入错误日志这个关键功能.实现这个功能,可以选择使用第三方日志插件,也可以选择使用数据库,还可以自己写个简单的方法把错误信息记录到日志文件. 选择最后一种方法实现的时候, ...

  2. java 写文件 并发_记录一次Java文件锁引起的并发写文件问题

    背景 刚接手新项目,该项目是高并发的游戏日志服务端存储,一个项目适配多个游戏,很多特殊需求要兼容,刚开始接手,需要修复很多管道的数据,存储管道有两个,分别是MySQL和HDFS,数据消费自Kafka, ...

  3. 多线程并发知识,肝完这篇10W+字超详细的文章就够了

    大家好,我是Oldou,今天又到了我们的学习时间了,本文介绍的是多线程相关的知识,文中的内容可能不是很全,但是学习完一定会让自己掉发升级,内容比较多,但是我们千万别放弃,不懂的地方一定要主动花时间去理 ...

  4. Java 多线程 并发编程------超全面

    转载自:http://blog.csdn.net/escaflone/article/details/10418651 一.多线程 1.操作系统有两个容易混淆的概念,进程和线程. 进程:一个计算机程序 ...

  5. Java 多线程 并发编程

    转载自  Java 多线程 并发编程 一.多线程 1.操作系统有两个容易混淆的概念,进程和线程. 进程:一个计算机程序的运行实例,包含了需要执行的指令:有自己的独立地址空间,包含程序内容和数据:不同进 ...

  6. Android 数据库综述(二) 程序计算器与信号量来处理多线程并发问题

    Android 数据库综述(二) 程序计算器与信号量来处理多线程并发问题 多线程操作数据库,为处理并发问题,大家第一想到的是加锁操作 ,SQLite是文件级别的锁.SQLite3对于并发的处理机制是允 ...

  7. (四)Java中的多线程之间实现同步+多线程并发同步

    一.什么是线程安全问题 为什么有线程安全问题? 当多个线程同时共享同一个全局变量或静态变量,做写的操作(修改变量值)时,可能会发生数据冲突问题,也就是线程安全问题.但是做读操作时不会发生数据冲突问题. ...

  8. futuretask java 并发请求_Java面试题整理一(侧重多线程并发)

    1..是否可以在static环境中访问非static变量? 答:static变量在Java中是属于类的,它在所有的实例中的值是一样的.当类被Java虚拟机载入的时候,会对static变量进行初始化.如 ...

  9. java sqlite 多线程并发_C#_C#解决SQlite并发异常问题的方法(使用读写锁),本文实例讲述了C#解决SQlite并 - phpStudy...

    C#解决SQlite并发异常问题的方法(使用读写锁) 本文实例讲述了C#解决SQlite并发异常问题的方法.分享给大家供大家参考,具体如下: 使用C#访问sqlite时,常会遇到多线程并发导致SQLI ...

最新文章

  1. LeetCode简单题之较大分组的位置
  2. linux命令行中curl和wget自动解压功能对比
  3. python中数据分析的流程为-在数据分析流程中整合Python和R(一)
  4. Oracle 数据库DBA管理手册!
  5. aspnet登录界面代码_SPA+.NET Core3.1 GitHub第三方授权登录
  6. VTK:Utilities之2DArray
  7. cd mysql 权限不够_.bash_profile权限不够_cdmysql权限不够
  8. 关于设计模式的胡思乱想
  9. C#开发笔记之21-C#解析Json(序列化/反序列化)的最佳实践。
  10. Mysql学习总结(79)——MySQL常用函数总结
  11. 1020. 月饼 (25)-PAT乙级真题
  12. 二、2.4版本之前的apache的安装
  13. java+jquery实现长轮询案例_网页实时聊天之js和jQuery实现ajax长轮询
  14. Unity中UI界面颤抖解决方法
  15. 利用Gabor变换法分析纹理图像 matlab代码实现
  16. Virtual Box创建共享目录
  17. 身份证地址码码表MySQL
  18. 数字签名的原理和应用
  19. java thread detach,C++语法学习笔记四十三:线程启动、结束,创建线程多法、join,detach...
  20. Mysql原理篇之索引不懂不要瞎用---04

热门文章

  1. Linux开机自动启动Tomcat
  2. Linux系统根据端口号查找项目路径
  3. 数学一年级应用题_【专项练习】一年级下册数学100以内加减法应用题专项练习,附答案...
  4. skywalking mysql配置_skywalking 配置和使用(windows)
  5. 管理mysql表知识点,数据库知识点整理(全)
  6. 第四章 ASP.NET MVC HTML.ActionLink输出超链接的具体用法
  7. Python入门--字符串的连接和替换,replace,join
  8. 单机 docker 部署fastfds_云服务器使用docker可视化一键部署Wrodpress个人博客,操作简单,适合小白...
  9. _软件园三期西片区F地块举行招商推介会 超300家企业意向落户 - 本网原创
  10. MySQL48道经典基础面试题(包含各个方面)