话不多说,先直接上代码:

主方法:

import java.util.concurrent.CountDownLatch;/*** @ProjectName: emp_customer* @Package: PACKAGE_NAME* @ClassName: Test* @Author: Administrator* @Description: ${description}* @Date: 2019/10/11 14:10* @Version: 1.0*/
public class Test {public static void main(String args[]){//线程数int threadSize=4;//源文件地址String sourcePath = "E:\\1\\4.txt";//目标文件地址String destnationPath = "E:\\2\\4.txt";//CountDownLatch latch = new CountDownLatch(threadSize);MultiDownloadFileThread m = new MultiDownloadFileThread(threadSize, sourcePath, destnationPath, latch);long startTime = System.currentTimeMillis();try {m.excute();latch.await();} catch (InterruptedException e) {e.printStackTrace();}long endTime = System.currentTimeMillis();System.out.println("全部下载结束,共耗时" + (endTime - startTime) / 1000 + "s");}}

线程类:

import java.io.*;
import java.nio.channels.FileChannel;
import java.nio.channels.FileLock;
import java.util.concurrent.CountDownLatch;/*** @ProjectName: emp_customer* @Package: PACKAGE_NAME* @ClassName: MultiDownloadFileThread* @Author: Administrator* @Description: ${description}* @Date: 2019/10/11 15:03* @Version: 1.0*/
public class MultiDownloadFileThread {private int threadCount;private String sourcePath;private String targetPath;private CountDownLatch latch;public MultiDownloadFileThread(int threadCount, String sourcePath, String targetPath, CountDownLatch latch) {this.threadCount = threadCount;this.sourcePath = sourcePath;this.targetPath = targetPath;this.latch = latch;}public void excute() {File file = new File(sourcePath);int fileLength = (int) file.length();//分割文件int blockSize = fileLength / threadCount;for (int i = 1; i <= threadCount; i++) {//第一个线程下载的开始位置int startIndex = (i - 1) * blockSize;int endIndex = startIndex + blockSize - 1;if (i == threadCount) {//最后一个线程下载的长度稍微长一点endIndex = fileLength;}System.out.println("线程" + i + "下载:" + startIndex + "字节~" + endIndex + "字节");new DownLoadThread(i, startIndex, endIndex).start();}}public class DownLoadThread extends Thread {private int i;private int startIndex;private int endIndex;public DownLoadThread(int i, int startIndex, int endIndex) {this.i = i;this.startIndex = startIndex;this.endIndex = endIndex;}@Overridepublic void run() {File file = new File(sourcePath);FileInputStream in = null;RandomAccessFile raFile = null;FileChannel fcin = null;FileLock flin = null;try {in = new FileInputStream(file);in.skip(startIndex);//给要写的文件加锁raFile = new RandomAccessFile(targetPath, "rwd");fcin =raFile.getChannel();while(true){try {flin = fcin.tryLock();break;} catch (Exception e) {System.out.println("有其他线程正在操作该文件,当前线程休眠1000毫秒,当前进入的线程为:"+i);sleep(1000);}}//随机写文件的时候从哪个位置开始写raFile.seek(startIndex);int len = 0;byte[] arr = new byte[1024];//获取文件片段长度int segLength = endIndex - startIndex + 1;while ((len = in.read(arr)) != -1) {if (segLength > len) {segLength = segLength - len;raFile.write(arr, 0, len);} else {raFile.write(arr, 0, segLength);break;}}System.out.println("线程" + i + "下载完毕");//计数值减一latch.countDown();} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException | InterruptedException e) {e.printStackTrace();} finally {try {if (in != null) {in.close();}if (raFile != null) {raFile.close();}} catch (IOException e) {e.printStackTrace();}}}}
}

运行结果:

涉及到的相关知识点:

1.CountDownLatch

2.RandomAccessFile

3.FileLock

下面我们具体讲解下

一、FileLock :文件锁

FileLock是java 1.4 版本后出现的一个类,它可以通过对一个可写文件(w)加锁,保证同时只有一个进程可以拿到文件的锁,这个进程从而可以对文件做访问;而其它拿不到锁的进程要么选择被挂起等待,要么选择去做一些其它的事情, 这样的机制保证了众进程可以顺序访问该文件。

1. 概念

  • 共享锁: 共享读操作,但只能一个写(读可以同时,但写不能)。共享锁防止其他正在运行的程序获得重复的独占锁,但是允许他们获得重复的共享锁。
  • 独占锁: 只有一个读或一个写(读和写都不能同时)。独占锁防止其他程序获得任何类型的锁。

2. lock()和tryLock()的区别:

lock()阻塞的方法,锁定范围可以随着文件的增大而增加。无参lock()默认为独占锁;有参lock(0L, Long.MAX_VALUE, true)为共享锁。
tryLock()非阻塞,当未获得锁时,返回null.
3. FileLock的生命周期:在调用FileLock.release(),或者Channel.close(),或者JVM关闭

4. FileLock是线程安全的

二、RandomAccessFile

java除了File类之外,还提供了专门处理文件的类,即RandomAccessFile(随机访问文件)类。该类是Java语言中功能最为丰富的文件访问类,它提供了众多的文件访问方法。RandomAccessFile类支持“随机访问”方式,这里“随机”是指可以跳转到文件的任意位置处读写数据。在访问一个文件的时候,不必把文件从头读到尾,而是希望像访问一个数据库一样“随心所欲”地访问一个文件的某个部分,这时使用RandomAccessFile类就是最佳选择。

RandomAccessFile对象类有个位置指示器,指向当前读写处的位置,当前读写n个字节后,文件指示器将指向这n个字节后面的下一个字节处。刚打开文件时,文件指示器指向文件的开头处,可以移动文件指示器到新的位置,随后的读写操作将从新的位置开始。RandomAccessFile类在数据等长记录格式文件的随机(相对顺序而言)读取时有很大的优势,但该类仅限于操作文件,不能访问其他的I/O设备,如网络、内存映像等。RandomAccessFile类的构造方法如下所示:

RandomAccessFile(File file ,  String mode)
//创建随机存储文件流,文件属性由参数File对象指定

RandomAccessFile(String name ,  String mode)
//创建随机存储文件流,文件名由参数name指定

这两个构造方法均涉及到一个String类型的参数mode,它决定随机存储文件流的操作模式,其中mode值及对应的含义如下:

“r”:以只读的方式打开,调用该对象的任何write(写)方法都会导致IOException异常
“rw”:以读、写方式打开,支持文件的读取或写入。若文件不存在,则创建之。
“rws”:以读、写方式打开,与“rw”不同的是,还要对文件内容的每次更新都同步更新到潜在的存储设备中去。这里的“s”表示synchronous(同步)的意思
“rwd”:以读、写方式打开,与“rw”不同的是,还要对文件内容的每次更新都同步更新到潜在的存储设备中去。使用“rwd”模式仅要求将文件的内容更新到存储设备中,而使用“rws”模式除了更新文件的内容,还要更新文件的元数据(metadata),因此至少要求1次低级别的I/O操作

三、CountDownLatch

1.概念

  • countDownLatch这个类使一个线程等待其他线程各自执行完毕后再执行。
  • 是通过一个计数器来实现的,计数器的初始值是线程的数量。每当一个线程执行完毕后,计数器的值就-1,当计数器的值为0时,表示所有线程都执行完毕,然后在闭锁上等待的线程就可以恢复工作了。

2.源码

  • countDownLatch类中只提供了一个构造器:
//参数count为计数值
public CountDownLatch(int count) {  };
  • 类中有三个方法是最重要的:
//调用await()方法的线程会被挂起,它会等待直到count值为0才继续执行
public void await() throws InterruptedException { };
//和await()类似,只不过等待一定的时间后count值还没变为0的话就会继续执行
public boolean await(long timeout, TimeUnit unit) throws InterruptedException { };
//将count值减1
public void countDown() { };  

假如在我们的代码里面,我们把main方法里面的

latch.await();

注释掉

如下所示:

我们可以看到跟之前的输出结果相比,我们的主方法里面输出的:全部下载结束的输出信息,已经打印到我们执行文件下载的线程输出信息的前面了,说明主线程先执行完。这从而说明,await() 方法具有阻塞作用

 我们在把latch.await();放开,把文件下载线程里的latch.countDown();注释掉,

如下:

我们可以看到,主程序里的的输出;全部下载结束的输出信息,一直未输出,程序也一直未结束,由此可得,countDown() 方法具有唤醒阻塞线程的作用。

那么如何让 CountdownLatch 尽早结束

假如我们的程序执行到countDown()之前就抛出异常,这就可能导致一整情况,CountdownLatch 计数永远不会达到零并且 await() 永远不会终止。

为了解决这个问题,我们在调用 await() 时添加一个超时参数。

CountDownLatch总结:

    1、CountDownLatch end = new CountDownLatch(N); //构造对象时候 需要传入参数N

  2、end.await()  能够阻塞线程 直到调用N次end.countDown() 方法才释放线程,最好设置超时参数

  3、end.countDown() 可以在多个线程中调用  计算调用次数是所有线程调用次数的总和

对于,本demo而言,加不加文件锁的意义不大,因为在进入线程写的时候,就已经告诉单个线程需要写的内容是哪一块到哪一块,不加锁,也会正常写入,切经本人测试无误,但若是对同一个文件,即要写,又要读话,就必须加锁,不然程序执行可能不完整,具体情况可以查看下面的这个博客:https://blog.csdn.net/gxy3509394/article/details/7435993

java 多个线程同时写同一个文件相关推荐

  1. java. tcp. 权限,java - tcpdump的不能够写PCAP文件。没有权限 - SO中文参考 - www.soinside.com...

    我开发我的Java应用程序,所以我可以在我的机器接口的数据包嗅探和转储结果滚动PCAP文件的网络监控解决方案.当从Java代码启动(使用sudo)tcpdump命令,我得到tcpdump: /path ...

  2. python多线程写同一个文件_Python多线程快速写入文件,python,飞速

    Python多线程快速写入文件,python,飞速 发表时间:2020-07-10 乱序多线程写入 举个最简单的例子,只要求快速写入即可,对顺序无要求时: import threading def w ...

  3. 多进程写同一个日志文件时如何确保每条日志不与其他日志重叠

    背景/ write + O_APPEND 可以实现多进程写相同日志不交叉 我们有多个进程,往同一个文件写日志.当然希望能每条日志边界清晰,既不与其他日志重叠,也不与其他日志交叉.为了达到这个目的,最直 ...

  4. 解决多进程或多线程同时读写同一个文件的问题

    解决多进程或多线程同时读写同一个文件的问题 PHP是没有多线程概念的,尽管如此我们仍然可以用"不完美"的方法来模拟多线程.简单的说,就是队列处理. 通过对文件进行 加锁和解锁 来实 ...

  5. java 多进程写一个文件_java高并发多线程及多进程同时写入文件研究

    测试&思考: 环境:windows 七.linux centos 6.三.java8html java多线程同时写一个文件 java高并发环境下多线程同时写入一个文件时, 经过 FileLoc ...

  6. java多线程读取文件_java多线程读写同一个文件

    本文提供java多线程分别定时读写同一个文件的样例,其中两个线程,一个每分钟写入当前时间到指定文件,另一个线程读出每分钟新写的内容. 使用简单的Thread.sleep技术实现定时 package t ...

  7. java多线程 文件夹_java多线程读同一个文件

    java多线程同时读取一个文件,这个方法可行吗?不可行. 多线程能够提高效率是因为现在的cpu普遍是多核cpu, 多条线程可以在多个内核中同时执行来提高计算效率.但是计算机磁盘的磁头只有一个,即使多条 ...

  8. Python 多进程向同一个文件写数据

    1.遇到的问题: 之前,因为考虑到Python多进程可以充分利用CPU核数,提高程序的效率,所以就使用多进程写文件.但是向同一个文件写入数据的时候,由于多进程是并发进行,操作系统中会不清楚到底要写入哪 ...

  9. Java 线程实时读取日志文件

    古怪的需求 在实习的公司碰到一个古怪的需求:在一台服务器上写日志文件,每当日志文件写到一定大小时,比如是1G,会将这个日志文件改名成另一个名字,并新建一个与原文件名相同的日志文件,再往这个新建的日志文 ...

最新文章

  1. 微信分享给朋友无响应
  2. linux shell编程学习笔记(9)正则表达式
  3. AtCoder AGC036E ABC String
  4. linux驱动(七)gpiolib库详解
  5. (java)短时间批量访问数据库(oracle)小结
  6. 初学JavaWeb,前端css要不要了解一下啊?一文学会JavaWeb中css的简单应用
  7. QtCreator 如何将开发的程序打包成exe
  8. ajax success返回 .net,asp.net-mvc-返回JsonResult的ASP.Net MVC Ajax调用
  9. Objections vs. excuses
  10. 【clickhouse】yandex 官方 BalancedClickhouseDataSource 源码分析
  11. java 拦截指定jsp_详解Struts2中对未登录jsp页面实现拦截功能
  12. chrome插件-显示在地址栏的二维码
  13. java arraystoreexception_java基础面试
  14. Atitit 作用域的理解attilax总结 1.1. 作用域是指对某一变量和方法具有访问权限的代码空间, 1 1.2. 作用域的使用提高了程序逻辑的局部性,增强程序的可靠性,减少名字冲突。 1 1
  15. 困了累了到底喝啥?浅谈饮料品牌如何进行推广策略定位
  16. Calibre电子书简繁转换
  17. 清华大学计算机相关夏令营,夏令营报名
  18. python爬取知乎热搜_python爬取知乎
  19. Android Studio 卡在Download fastutil-8.4.0-sources jar以及New Module为灰色的问题及解决方法
  20. cgb2111-day02

热门文章

  1. 【算法】最长公共子序列(LCS)
  2. 【数学模拟卷总结】2022李林四套卷数学二第四套
  3. 对称加密——AES算法使用
  4. idea编译报错:Refer to the generated Javadoc files in ‘..\target\apidocs‘ dir. 解决
  5. 【STM32利用CuBe MX生成HID设备】2-给游戏控制器添加X\Y轴
  6. 去掉数组中重复出现元素的算法
  7. 惠众和环宇计算机专业,计算机一级Office
  8. 【计算机视觉】关于用opencv 设置摄像头读分辨率问题的若干说明
  9. ImageJ对荧光信号离散的细胞计数方法
  10. 网络同步时钟系统_NTP时间服务器