Java多线程复制文件

Java多线程方式复制文件

**这几日有一个数据迁移需求,是说从一个系统中将所有的图片按照新的规则迁移到新的系统中来。**

思路如下

1. 使用生产者模式将要下载的清单放到一个阻塞队列里面。
2. 执行消费者模式读取文件并进行处理。

其核心代码如下

生产者

//生产者
import java.util.concurrent.BlockingQueue;
public class Producer implements Runnable {  
    private BlockingQueue<FilesRes> queue;  
    private FilesRes produce;  
    public Producer(BlockingQueue<FilesRes> queue, FilesRes produce) {  
        this.queue = queue;  
        if (null != produce)  
            this.produce = produce;  
        else this.produce = null;  
    }  

    @Override  
    public void run() {  
        try {  
            queue.put(produce);  //当队列里满的话,会阻塞 
        } catch (InterruptedException e) {  
            System.out.println(e.getMessage());  
        }  
    }  
}

消费者

//消费者
import java.io.File;
import java.io.IOException;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.commons.io.FileUtils;


public class Consumer implements Runnable {  
    private BlockingQueue<FilesRes> queue;  

    private static AtomicInteger atomic = new AtomicInteger(0);//初始化计数器

    public Consumer(BlockingQueue<FilesRes> queue) {  
        this.queue = queue;  
    }  

    @Override  
    public void run() {  
        try {
            FilesRes filesRes = queue.take();     //当队列里是空的话,会阻塞 
            String nameFiles = "E:/Source/CopyPhotossss/" ;
            File file = new File(filesRes.getUrl());
            File ofile = new File(nameFiles+filesRes.getFileName());
            FileUtils.copyFile(file, ofile, true);
            //使用的是commons-io工具包
        } catch (InterruptedException e) {  
            System.out.println(e.getMessage());  
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }  
    }  
} 

JavaBean:里面只是保存了一下文件的路径,在这个测试里面没有多少实际意义

public class FilesRes {
    private String fileName;
    private String url;
    private String idCard;
    /**
 * 
 * @param fileName 文件名
 * @param url 路径
 * @param idCard 身份证
 */
    public FilesRes(String fileName, String url, String idCard) {
        super();
        this.fileName = fileName;
        this.url = url;
        this.idCard = idCard;
    }
    ...get和set 方法省略
}

测试类:

import java.io.File;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.LinkedBlockingQueue;

public class Tester {
    public static void main(String[] args) throws InterruptedException {
        long starTime=System.currentTimeMillis();
        LinkedBlockingQueue<FilesRes> queue = new LinkedBlockingQueue<FilesRes>(10);  
        //线程池 操作
        ExecutorService service = Executors.newCachedThreadPool();  
        String sourceFile = "E:/Source/Photos";
        File file = new File(sourceFile);
        File [] files = file.listFiles();
        for (File filename : files) {
            FilesRes filesRes = new FilesRes(filename.getName(),filename.getAbsolutePath(),filename.getName());
            service.submit(new Producer(queue, filesRes));  
        }
        //开始
        for (int i = 0; i < files.length; i++) {
            service.submit(new Consumer(queue));
        }
        service.shutdown();
        while(true){//用于判断是否已经导完
            if(service.isTerminated()){
                System.out.println("文件已经迁移成功!");
                long endTime=System.currentTimeMillis();
                long time=endTime-starTime;
                System.out.println(time);
                break;
            }
            Thread.sleep(200);
        }
    }  
}  

搞定,但是代码最后判断是否已经导入完毕的时候,使用了轮询方式去遍历不是很理想。查了写资料,虽然也有其他方式,但是比较麻烦。在研究的过程中,我发现了一个非常好用的disruptor架构提供的生产者和消费者模式有这个功能,很不错。
具体的使用可以看下面的连接,我就不再阐述了。

disruptor-3.3.2源码解析
(序列)http://www.myexception.cn/open-source/2036769.html
(队列)http://www.myexception.cn/open-source/2036766.html
(发布事件)http://www.myexception.cn/open-source/2036781.html
(处理事件)http://www.myexception.cn/open-source/2036779.html
(框架支持)http://www.myexception.cn/open-source/2036776.html

最后我把代码贴一些,有兴趣的人可以调一下

package disruptor;

import java.io.File;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import com.lmax.disruptor.EventFactory;
import com.lmax.disruptor.IgnoreExceptionHandler;
import com.lmax.disruptor.RingBuffer;
import com.lmax.disruptor.SequenceBarrier;
import com.lmax.disruptor.WorkHandler;
import com.lmax.disruptor.WorkerPool;
import com.lmax.disruptor.YieldingWaitStrategy;
 public class Demo3 {  
    public static void main(String[] args) throws InterruptedException {
        long starTime=System.currentTimeMillis();
        int BUFFER_SIZE=1024 * 1024 * 2;         
        RingBuffer<FilesRes> ringBuffer = RingBuffer.createSingleProducer(new EventFactory<FilesRes>() {
            @Override
            public FilesRes newInstance() {
                return new FilesRes();
            }
        },BUFFER_SIZE,new YieldingWaitStrategy());
        SequenceBarrier sequenceBarrier = ringBuffer.newBarrier();  
        ExecutorService executor = Executors.newFixedThreadPool(2); 
        WorkHandler<FilesRes> workHandlers=new FilesWorkHandlers();  
        WorkerPool<FilesRes> workerPool=new WorkerPool<FilesRes>(ringBuffer, sequenceBarrier, new IgnoreExceptionHandler(), workHandlers);  
        workerPool.start(executor);  
        String sourceFile = "E:/Source/Photos";
        //下面这个生产8个数据,图简单就写到主线程算了 

        File file = new File(sourceFile);
        File [] files = file.listFiles();
        for (File filename : files) {

            long seq=ringBuffer.next();
            try{
                FilesRes filesRes = ringBuffer.get(seq);
                filesRes.setFileName(filename.getName());
                filesRes.setUrl(filename.getAbsolutePath());
                filesRes.setIdCard(filename.getName());
            }finally{
                ringBuffer.publish(seq);
                System.out.println(seq);
            }
        }
        workerPool.drainAndHalt();//任务完成后关闭 线程会在这里堵塞 (太爱了,不用判断是否所有的线程都完毕了,哦也)
        executor.shutdown(); 
        long endTime=System.currentTimeMillis();
        long time=endTime-starTime;
        System.out.println(time);   
    }  
}  
package disruptor;
import java.io.File;

import org.apache.commons.io.FileUtils;

import com.lmax.disruptor.EventHandler;
import com.lmax.disruptor.WorkHandler;

public class FilesWorkHandlers implements EventHandler<FilesRes>,WorkHandler<FilesRes>{

    @Override
    public void onEvent(FilesRes filesRes) throws Exception {
        //System.out.println(filesRes.getUrl());
        String nameFiles = "E:/Source/CopyPhoto2/" ;
        File file = new File(filesRes.getUrl());
        File ofile = new File(nameFiles+filesRes.getFileName());
        FileUtils.copyFile(file, ofile, true);
    }

    @Override
    public void onEvent(FilesRes arg0, long arg1, boolean arg2)
            throws Exception {
        // TODO Auto-generated method stub

    }

}

怎么样是不是代码更加优雅简洁呢?

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

竖子敢尔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值