29多线程(线程池定时器)将一个文件复制多次拆分文件并合并多线程复制文件

Posted ShawnYue-08

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了29多线程(线程池定时器)将一个文件复制多次拆分文件并合并多线程复制文件相关的知识,希望对你有一定的参考价值。

线程池

程序启动一个新线程成本是比较高的,因为它涉及到与操作系统交互。而使用线程池可以很好的提高性能,尤其是

当程序中要创建大量生存期很短的线程时,更应该考虑使用线程池。

线程池里的每一个线程代码结束后,并不会死亡,而是再次回到线程池中成为空闲状态,等待下一个对象来使用。

在JDK 5之前,我们必须手动实现自己的线程池,从JDK 5开始,Java内置支持线程池。

package org.westos.demo;

import java.util.concurrent.*;

/**
 * @author lwj
 * @date 2020/6/7 8:36
 */
public class MyTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        /*
        线程池:容器,存有一定数量线程对象的容器
        JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法
		public static ExecutorService newCachedThreadPool():			根据任务的数量来创建线程对应的线程个数
		public static ExecutorService newFixedThreadPool(int nThreads):	固定初始化几个线程
		public static ExecutorService newSingleThreadExecutor():			初始化一个线程的线程池
        这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnable对象或者Callable对象代表的线程。它提供了如下方法
            Future<?> submit(Runnable task)
            <T> Future<T> submit(Callable<T> task)
        使用步骤:
            创建线程池对象
            创建Runnable实例
            提交Runnable实例
            关闭线程池
         */
        ExecutorService executorService = Executors.newCachedThreadPool();
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("线程执行了这个任务");
            }
        });
        //根据任务数量创建相应数量的线程对象
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println("提交第二个任务");
            }
        });
        Future<Integer> submit = executorService.submit(new MyCallable());
        System.out.println(submit.get());

        executorService.shutdown();
        //关闭线程池
    }
}

class MyCallable implements Callable<Integer> {

    @Override
    public Integer call() throws Exception {
        return 100;
    }
}
package org.westos.demo2;

import java.util.concurrent.*;

/**
 * @author lwj
 * @date 2020/6/7 8:36
 */
public class MyTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        /*
        线程池:容器,存有一定数量线程对象的容器
        JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法
		public static ExecutorService newCachedThreadPool():			根据任务的数量来创建线程对应的线程个数
		public static ExecutorService newFixedThreadPool(int nThreads):	固定初始化几个线程
		public static ExecutorService newSingleThreadExecutor():			初始化一个线程的线程池
        这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnable对象或者Callable对象代表的线程。它提供了如下方法
            Future<?> submit(Runnable task)
            <T> Future<T> submit(Callable<T> task)
        使用步骤:
            创建线程池对象
            创建Runnable实例
            提交Runnable实例
            关闭线程池
         */
        ExecutorService executorService = Executors.newFixedThreadPool(5);
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        });
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        });
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        });
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        });

        executorService.shutdown();
    }
}
package org.westos.demo3;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author lwj
 * @date 2020/6/7 8:36
 */
public class MyTest {
    public static void main(String[] args) throws ExecutionException, InterruptedException {
        /*
        线程池:容器,存有一定数量线程对象的容器
        JDK5新增了一个Executors工厂类来产生线程池,有如下几个方法
		public static ExecutorService newCachedThreadPool():			根据任务的数量来创建线程对应的线程个数
		public static ExecutorService newFixedThreadPool(int nThreads):	固定初始化几个线程
		public static ExecutorService newSingleThreadExecutor():			初始化一个线程的线程池
        这些方法的返回值是ExecutorService对象,该对象表示一个线程池,可以执行Runnable对象或者Callable对象代表的线程。它提供了如下方法
            Future<?> submit(Runnable task)
            <T> Future<T> submit(Callable<T> task)
        使用步骤:
            创建线程池对象
            创建Runnable实例
            提交Runnable实例
            关闭线程池
         */
        ExecutorService executorService = Executors.newSingleThreadExecutor();
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        });
        executorService.submit(new Runnable() {
            @Override
            public void run() {
                System.out.println(Thread.currentThread().getName());
            }
        });

        executorService.shutdown();
    }
}

定时器与定时任务

package org.westos.demo4;

import java.util.Timer;
import java.util.TimerTask;

/**
 * 定时器
 * @author lwj
 * @date 2020/6/7 9:28
 */
public class MyTest {
    public static void main(String[] args) {
        Timer timer = new Timer();
        //TimerTask抽象类
        MyTimerTask myTimerTask = new MyTimerTask(timer);
        timer.schedule(myTimerTask, 3000);
        //等3s后执行该定时任务

        // 取消定时器
        // timer.cancel();
    }
}

class MyTimerTask extends TimerTask {
    public Timer timer;

    public MyTimerTask(Timer timer) {
        this.timer = timer;
    }

    @Override
    public void run() {
        System.out.println("时间到了");
        timer.cancel();
    }
}
package org.westos.demo4;

import java.util.Timer;
import java.util.TimerTask;

/**
 * @author lwj
 * @date 2020/6/7 9:36
 */
public class MyTest2 {
    public static void main(String[] args) {
        Timer timer = new Timer();
        MyTimerTask2 myTimerTask2 = new MyTimerTask2();
        timer.schedule(myTimerTask2, 3000, 1000);
        //等3s后执行此任务,以后间隔1s重复执行定时任务
    }
}

class MyTimerTask2 extends TimerTask {

    @Override
    public void run() {
        System.out.println("时间到了");
    }
}
package org.westos.demo4;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.LocalDateTime;
import java.util.Date;
import java.util.Timer;
import java.util.TimerTask;

/**
 * @author lwj
 * @date 2020/6/7 9:38
 */
public class MyTest3 {
    public static void main(String[] args) throws ParseException {
        Timer timer = new Timer();
        MyTimerTask3 myTimerTask3 = new MyTimerTask3();
        //myTimerTask2.cancel(); 取消定时任务

        String str = "2020-06-07 09:49:00";
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        Date parse = sdf.parse(str);

        timer.schedule(myTimerTask3, parse);
        //指定某个时间执行定时任务
    }
}

class MyTimerTask3 extends TimerTask {

    @Override
    public void run() {
        System.out.println("时间到了");
    }
}

指定时间删除文件夹

package org.westos.demo4;

import java.io.File;
import java.util.Timer;
import java.util.TimerTask;

/**
 * 定时删除一个文件夹
 * @author lwj
 * @date 2020/6/7 9:49
 */
public class MyDemo {
    public static void main(String[] args) {
        Timer timer = new Timer();
        //定时器

        File source = new File("E:\\新建文件夹");
        TimerTaskDemo timerTaskDemo = new TimerTaskDemo(source, timer);

        timer.schedule(timerTaskDemo, 5000);
        //延迟5s后执行定时任务,删除文件夹
    }
}

class TimerTaskDemo extends TimerTask {
    public File directory;
    public Timer timer;

    public TimerTaskDemo(File directory, Timer timer) {
        this.directory = directory;
        this.timer = timer;
    }

    @Override
    public void run() {
        //删除文件夹并关闭定时器
        deleteDir(directory);
        timer.cancel();
        //取消定时器
    }

    public void deleteDir(File file) {
        if (file.isDirectory()) {
            File[] files = file.listFiles();
            for (File file1 : files) {
                deleteDir(file1);
            }
        }
        file.delete();
        //删除文件或者空文件夹
    }
}

练习题

1、把一个文件复制多次

package org.westos.demo5;

import java.io.*;

/**
 * @author lwj
 * @date 2020/6/7 15:11
 */
public class MyTest {
    public static void main(String[] args) throws IOException {
        File source = new File("C:\\Users\\shawn\\Music\\MV\\G.E.M. 邓紫棋-我说了算(多芬秀发合作单曲)(蓝光).mp4");
        RandomAccessFile rw = new RandomAccessFile(source, "rw");
        byte[] bytes = new byte[1024 * 8];
        int len = 0;
        for (int i = 0; i < 3; i++) {
            FileOutputStream fos = new FileOutputStream(new File("E:\\music", "G.E.M" + i + ".mp4"));
            while ((len = rw.read(bytes)) != -1) {
                fos.write(bytes, 0, len);
                fos.flush();
            }
            fos.close();
            //每复制一个文件,将随机读取流的指针重置为0
            rw.seek(0);
        }
        rw.close();
    }
}

2、拆分文件并合并

package org.westos.demo5;

import java.io.*;
import java.util.Arrays;
import java.util.Enumeration;
import java.util.Vector;

/**
 * @author lwj
 * @date 2020/6/7 15:24
 */
public class MyTest2 {
    public static void main(String[] args) throws IOException {
        split();
        merge();
    }

    private static void merge() throws IOException {
        File source = new File(".");
        System.out.println(source.getAbsolutePath());
        File[] files = source.listFiles(new FileFilter() {
            @Override
            public boolean accept(File pathname) {
                return pathname.isFile() && pathname.length() <= 1024 * 1024 && pathname.getName().endsWith(".mp3");
            }
        });
        Vector<FileInputStream> vector = new Vector<>();
        for (File file : files) {
            vector.addElement(new FileInputStream(file));
        }
        Enumeration<FileInputStream> elements = vector.elements();
        SequenceInputStream sis = new SequenceInputStream(elements);

        byte[] bytes = new byte[1024];
        int len = 0;
        FileOutputStream fos = new FileOutputStream(new File("百事.mp3"));
        while ((len = sis.read(bytes)) != -1) {
            fos.write(bytes, 0, len);
            fos.flush();
        }
        fos.close();
        sis.close();
    }

    private static void split() throws IOException {
        //把一份文件拆分为多份,每份1M,然后合并
        File source = new File("C:\\Users\\shawn\\Music\\G.E.M. 邓紫棋 _ 王嘉尔 - 热爱就一起.mp3");

        FileInputStream fis = new FileInputStream(source);
        byte[] bytes = new byte[1024 * 1024];
        int len = 0;
        int index = 0;
        while ((len = fis.read(bytes)) != -1) {
            FileOutputStream fos = new FileOutputStream(new File(index++ + ".mp3"));
            fos.write(bytes, 0, len);
            fos.close();
        }
        fis.close();
    }
}

3、多线程复制文件

package org.westos.demo5;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.RandomAccessFile;

/**
 * @author lwj
 * @date 2020/6/7 15:49
 */
public class MyDemo {
    public static void main(String[] args) throws FileNotFoundException {
        //多线程复制同一份文件
        File source = new File("C:\\Users\\shawn\\Music\\G.E.M. 邓紫棋 _ 王嘉尔 - 热爱就一起.mp3");
        File destFile = new File(".\\邓紫棋-热爱就一起.mp3");
        long length = source.length();
        //文件的总大小
        long threadNums = 3;
        long average = length / threadNums;
        for (int i = 0; i < 3; i++) {
            long start = i * (average + 1);
            long end = (i + 1) * average;
            new CopyFileThread(start, end, source, destFile).start();
        }
        //如果3个线程不能均分,那么再添加一个线程
        if (length % threadNums != 0) {
            long start = threadNums * average + 1;
            new CopyFileThread(start, length, source, destFile).start();
        }
    }
}


class CopyFileThread extends Thread {
    public long start;
    public long end;
    public RandomAccessFile in;
    public RandomAccessFile out;

    public CopyFileThread(long start, long end, File srcFile, File destFile) throws FileNotFoundException {
        this.start = start;
        this.end = end;
        this.in = new RandomAccessFile(srcFile, "rw");
        this.out = new RandomAccessFile(destFile, "rw");
    }

    @Override
    public void run() {
        try {
            in.seek(start);
            out.seek(start);
            //设置读写起始指针
            byte[] bytes = new byte[1024 * 8];
            int len = 0;
            long pointer = in.getFilePointer();
            while (pointer <= end && (len = in.read(bytes)) != -1) {
                //最后一次有可能只剩余1KB,然而最后一次还是会读取8KB,然后pointer > end退出while
                out.write(bytes, 0, len);
                pointer += len;
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
}

以上是关于29多线程(线程池定时器)将一个文件复制多次拆分文件并合并多线程复制文件的主要内容,如果未能解决你的问题,请参考以下文章

定时任务多线程的实现

线程Queue定时器进程池和线程池同步异步

线程重复执行问题与线程池

Java多线程与并发库高级应用-线程池

spring定时任务.线程池,自定义多线程配置

spring定时任务.线程池,自定义多线程配置