新浪面试题-多线程合并文件

今日我收到了一封来自新浪面试的面试邮件,里面就有一道面试题。就是要求多线程合并一个文件,写我整整两天的时间搞定这个题目,给大家分享一下,看代码。

主程序

package com.huang;

import org.apache.log4j.Logger;

import java.util.concurrent.*;

/**
 * 主程序,本程序采用生产者消费者模型,对多个文件进行读写操作
 * Created by root on 16-9-1.
 */
public class Main {
    private static final Logger MAIN_LOGGER=Logger.getLogger(Main.class);
    private static final Logger CON_LOGGER=Logger.getLogger(Consumer.class);
    private static final Logger PRO_LOGGER=Logger.getLogger(Producer.class);
    private static final  ExecutorService POOL;
    //使用阻塞队列实现生产者消费者
    private static final BlockingQueue BLOCKING_QUEUE = new LinkedBlockingQueue();

    static{
        //获取CPU核数
        int cpuNum=Runtime.getRuntime().availableProcessors();
        //因为是IO密集型的程序,如果是CPU密集型程序则N+1
        POOL= Executors.newFixedThreadPool(2*cpuNum+1);
    }

    public static void main(String args[]){
        String in[]={"/tmp/a","/tmp/b","/tmp/c"};
        String out="/tmp/d";
        for(int i=0;i<in.length;i++){
            POOL.execute(new Producer(BLOCKING_QUEUE,in[i],PRO_LOGGER));
        }
        POOL.shutdown();
        new Thread(new Consumer(BLOCKING_QUEUE,CON_LOGGER,out,in.length)).start();
    }

}

生产者

package com.huang;

import org.apache.log4j.Logger;

import java.io.IOException;
import java.util.concurrent.BlockingQueue;


/**
 * 生产者
 * Created by root on 16-8-31.
 */
public class Producer implements Runnable{
    private BlockingQueue<Byte[]> blockingQueue;
    private String filePath;
    private Logger logger;

    public Producer(BlockingQueue blockingQueue,String filePath,Logger logger) {
        this.blockingQueue=blockingQueue;
        this.filePath=filePath;
        this.logger=logger;
    }
    @Override
    public void run() {
        try {
            Byte[] data=FileOperate.toArray(FileOperate.getFileByte(filePath));
            blockingQueue.add(data);
        } catch (IOException e) {
            logger.error(e.getMessage(),e);
        }
    }
}

消费者

package com.huang;

import org.apache.log4j.Logger;

import java.io.IOException;
import java.util.concurrent.BlockingQueue;

/**
 *消费者
 * Created by root on 16-8-31.
 */
public class Consumer implements Runnable{
    private final BlockingQueue<Byte[]> blockingQueue;
    private Logger logger;
    private String outFile;
    private int num;
    public Consumer(BlockingQueue blockingQueue,Logger logger,String outFile,int num){
        this.blockingQueue=blockingQueue;
        this.logger=logger;
        this.outFile=outFile;
        this.num=num;
    }
    @Override
    public void run() {
        while(true){
            try {
                Byte[] bytes=blockingQueue.take();
                FileOperate.writeByte(outFile,bytes);
                if(--num==0)
                    break;
            } catch (InterruptedException e) {
                logger.error(e.getMessage(),e);
            } catch (IOException e) {
                logger.error(e.getMessage(),e);
            }
        }
    }
}

文件操作工具类

package com.huang;

import java.io.*;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;

/**
 * Created by root on 16-8-31.
 */
public class FileOperate {
    /**
     * 使用NIO对文件进行写操作
     * @param filePath
     * @param bytes
     * @throws IOException
     */
    public static void  writeByte(String filePath,Byte[] bytes) throws IOException {
        Lock lock=new ReentrantLock();
        File outFile=new File(filePath);
        if(!outFile.exists())
            outFile.createNewFile();
        try(FileOutputStream fileOutputStream=new FileOutputStream(outFile,true); FileChannel fileChannel=fileOutputStream.getChannel();){
            ByteBuffer bf=ByteBuffer.wrap(getBytes(bytes));
            fileChannel.write(bf);
        }
    }

    /**
     *使用NIO对文件进行读操作
     * @param filePath
     * @return
     * @throws IOException
     */
    public static List<Byte> getFileByte(String filePath) throws IOException {
        File inFile=new File(filePath);
        List<Byte> bytes=null;
        try (FileInputStream fileInputStream= new FileInputStream(filePath); FileChannel fc=fileInputStream.getChannel();){
            bytes=new ArrayList<>();
            ByteBuffer bf=ByteBuffer.allocate(1024);
            while(fc.read(bf)!=-1) {
                bf.flip();
                while(bf.hasRemaining())
                    bytes.add(bf.get());
                bf.clear();
            }
        } catch (FileNotFoundException e) {

            throw new RuntimeException(filePath+"您输入的文件路径有误");
        }

        return bytes;
    }
    public static Byte[] toArray(List<Byte> list){
        Byte[] result=new Byte[list.size()];
        for(int i=0;i<list.size();i++){
            result[i]=list.get(i);
        }
        return result;
    }
    public static byte[] getBytes(Byte[] bytes){
        byte[] result=new byte[bytes.length];
        for(int i=0;i<result.length;i++){
            result[i]=bytes[i];
        }
        return result;
    }
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值