java day 31: thread pool, design mode
1. Overview and use of thread pool
A: Thread pool overview
Starting a new thread is expensive because it involves interacting with the operating system.
The use of thread pool can improve performance, especially when a large number of short-lived threads are to be created in the program, the use of thread pool should be considered.
After each thread code in the thread pool ends, it will not die. Instead, it will return to the thread pool again and become idle, waiting for the next object to use.
Before JDK5, we must manually implement our own thread pool. Starting from JDK5, Java has built-in support for thread pool
B: An overview of the use of the built-in thread pool
JDK5 has added an Executors factory class to generate thread pools. There are several methods as follows
public static ExecutorService newCachedThreadPool(): create the number of threads corresponding to the thread according to the number of tasks
public class MyTest { public static void main(String[] args) throws ExecutionException, InterruptedException { //Thread pool: a container containing a certain number of Thread objects. Thread pool can reuse and manage Thread objects. //JDK5 has added an Executors factory class to generate thread pools. There are several methods as follows // public static ExecutorService newCachedThreadPool(): number of threads corresponding to the number of tasks created //ExecutorService thread pool object ExecutorService executorService = Executors.newCachedThreadPool(); executorService.submit(new MyRunnale()); /* executorService.submit(new MyRunnale()); executorService.submit(new MyRunnale()); executorService.submit(new MyRunnale()); executorService.submit(new MyRunnale());*/ Future<Integer> future = executorService.submit(new MyCallable()); Integer integer = future.get(); System.out.println(integer); //Close thread pool executorService.shutdown(); } } class MyRunnale implements Runnable{ @Override public void run() { System.out.println(Thread.currentThread().getName()+"The thread performs this task"); } } class MyCallable implements Callable<Integer>{ @Override public Integer call() throws Exception { System.out.println("call Method executed"); return 100; } }
public static ExecutorService newFixedThreadPool(int nThreads): initializes several threads
public static void main(String[] args) { // Public static executorservice newfixedthreadpool (int nthreads): initializes several threads ExecutorService executorService = Executors.newFixedThreadPool(2); executorService.submit(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " 11111111111111111"); } }); executorService.submit(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " 11111111111111111"); } }); executorService.submit(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " 11111111111111111"); } }); executorService.submit(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " 11111111111111111"); } }); executorService.submit(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " 11111111111111111"); } }); executorService.submit(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " 111111111111111"); } }); executorService.submit(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " 11111111111111111"); } }); executorService.submit(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " 11111111111111111"); } }); executorService.submit(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " 11111111111111111"); } }); executorService.submit(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " 11111111111111111"); } }); executorService.submit(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " 11111111111111111"); } }); executorService.submit(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " 11111111111111111"); } }); //Close thread pool executorService.shutdown(); }
public static ExecutorService newSingleThreadExecutor(): initializes the thread pool of a thread
public static void main(String[] args) { // public static ExecutorService newSingleThreadExecutor(): initializes the thread pool of a thread ExecutorService executorService = Executors.newSingleThreadExecutor(); executorService.submit(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName()+" 111111"); } }); executorService.submit(new Runnable() { @Override public void run() { System.out.println(Thread.currentThread().getName() + " 111111"); } }); }
The return value of these methods is ExecutorService object, which represents a thread pool and can execute the thread represented by Runnable object or Callable object. It provides the following methods
Future<?> submit(Runnable task)
Future submit(Callable task)
Use steps:
Create thread pool object
Create Runnable instance
Submit Runnable instance
Close thread pool
C: Case study: use of thread pool
2. Implementation of multithreaded program by anonymous inner class
A: Case demonstration
Implementation of multithreaded program by anonymous inner class
new Thread() {code }.start();
new Thread(new Runnable() {code }).start();
3. overview and use of timer (understanding)
A: Timer overview
Timer is a widely used thread tool, which can be used to schedule multiple scheduled tasks to be executed by subsequent threads.
In Java, the function of defining schedule can be realized through Timer and TimerTask classes.
B:Timer and TimerTask
Timer:
public Timer()
public void schedule(TimerTask task, long delay):
public void schedule(TimerTask task,long delay,long period);
public void schedule(TimerTask task, Date time):
public void schedule(TimerTask task, Date firstTime, long period):
TimerTask: scheduled task
public abstract void run()
public boolean cancel()
Under development
Quartz is an open source scheduling framework written entirely in java.
C: Case study: use of timer
public class MyTest { public static void main(String[] args) { //Timer a tool used by a thread to schedule tasks to be performed later in a background thread. You can schedule tasks to be performed once, or repeatedly on a regular basis. Timer timer = new Timer(); //Let timer perform timing task MyTimerTask myTimerTask = new MyTimerTask(timer); //Wait 3 seconds to execute the task // timer.schedule(myTimerTask,3000); //Wait for 3 seconds to execute the task for the first time, and then repeat the scheduled task every 1 second timer.schedule(myTimerTask, 3000,1000); //Cancel scheduled task // myTimerTask.cancel(); //Cancel timer //timer.cancel(); } } class MyTimerTask extends TimerTask{ private Timer timer; public MyTimerTask(Timer timer) { this.timer = timer; } @Override public void run() { System.out.println("Touch! It exploded"); //Cancel timer // timer.cancel(); } }
4. Timer practice (understanding)
A: Case demonstration
Multiple execution code of timing task
public class MyTest2 { public static void main(String[] args) throws ParseException { Timer timer = new Timer(); //Perform scheduled tasks on a specified date MyTask task = new MyTask(); String dateStr="2020-06-07 09:48:00"; //Perform scheduled tasks on a specified date Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateStr); //Perform a scheduled task once on a specified date // timer.schedule(task,date); //Execute the task for the first time on the specified date, and repeat it every 1s timer.schedule(task, date,1000); //Exercise: delete a folder regularly } } class MyTask extends TimerTask{ @Override public void run() { System.out.println("The scheduled task is performed"); } }
Regularly delete the specified directory with content
public class MyTest { public static void main(String[] args) throws ParseException { Timer timer = new Timer(); String dateStr = "2020-06-07 10:16:00"; //Perform scheduled tasks on a specified date Date date = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse(dateStr); MyTask myTask = new MyTask(timer); timer.schedule(myTask,date); } } class MyTask extends TimerTask{ private Timer timer; public MyTask(Timer timer) { this.timer = timer; } @Override public void run() { File folder = new File("C:\\Users\\ShenMouMou\\Desktop\\demo"); deleteFolder(folder); //off timer timer.cancel(); System.out.println("Delete completed"); } private void deleteFolder(File folder) { File[] files = folder.listFiles(); for (File f : files) { if (f.isFile()) { f.delete(); }else{ deleteFolder(f); } } folder.delete(); } }
5. Common interview questions of multithreading (understanding)
A: There are several implementation schemes for multithreading, which are they? Three B: What are the three synchronization methods? Lock C: Is starting a thread run() or start()? What's the difference between them?
6. Overview and classification of design patterns (understanding)
A: Design pattern overview Design pattern is a set of repeated use, most people know, after classification, code design experience summary. Design patterns are used to reuse code, make it easier for others to understand, ensure code reliability and make code structure clearer B: Design pattern classification Creation mode (for creating objects): Singleton mode, abstract factory mode, builder mode, factory mode, prototype mode. Behavioral mode (object function): adapter mode, bridge mode, decoration mode, combination mode, appearance mode, enjoyment mode and agent mode. Structural pattern (object composition): template method pattern, command pattern, iterator pattern, observer pattern, mediator pattern, memo pattern, Interpreter pattern, state pattern, policy pattern, responsibility chain pattern, visitor pattern.
7. Overview and use of simple factory model (understanding)
A: Simple factory model overview:
Also known as static factory method pattern, it defines a specific factory class that is responsible for creating instances of some classes
B: Advantages:
The advantage of using the static factory pattern is to realize the division of responsibilities. The core of the pattern is the factory class, which contains necessary selection logic to decide when to create an instance of a product,
Clients, on the other hand, are exempt from the responsibility of creating products directly, and only consume products. That is to say, static factory mode can dynamically add products without changing the client code. Clarify the responsibilities of the class
C: Disadvantages
This static factory class is responsible for the creation of all objects. If new objects are added or some objects are created in different ways,
You need to modify the factory class constantly, which is not conducive to later maintenance
D: Case demonstration
//Factory class: mainly responsible for creating various animal instances public class AniamlFactory { private AniamlFactory() {} //Create a cat product /* public static Cat getCat(){ return new Cat();} public static Dog getDog() { return new Dog();} public static Tiger geTiger() { return new Tiger();}*/ public static Animal getAnimal(String name){ if("cat".equals(name)){return new Cat(); }else if("dog".equals(name)){return new Dog(); }else if("tiger".equals(name)){return new Tiger(); }else{return null; } } }
public abstract class Animal { public abstract void eat(); }
public class Cat extends Animal{ @Override public void eat() {System.out.println("Cats eat fish"); } }
public class Dog extends Animal{ @Override public void eat() { System.out.println("Dogs eat bones"); } }
public class Tiger extends Animal{ @Override public void eat() { System.out.println("Tiger eats chicken"); } }
public class MyTest { public static void main(String[] args) { /* Dog dog = AniamlFactory.getDog(); //use dog.eat(); //use Cat cat = AniamlFactory.getCat(); cat.eat(); Tiger tiger = AniamlFactory.geTiger(); tiger.eat();*/ Animal an = AniamlFactory.getAnimal("cat"); an.eat(); an=AniamlFactory.getAnimal("dog"); an.eat(); an=AniamlFactory.getAnimal("tiger"); an.eat(); } }
8. Design pattern (overview and use of factory method pattern) (understanding)
A: Overview of the factory approach model
In the factory method pattern, the abstract factory class is responsible for defining the interface for creating objects, and the creation of concrete objects is implemented by the concrete class that inherits the abstract factory.
B: Advantages
The client does not need to be responsible for the creation of objects, thus clarifying the responsibilities of each class. If there are new objects added,
It only needs to add a specific class and a specific factory class, which does not affect the existing code. It is easy to maintain in the later stage and enhances the expansibility of the system
C: Disadvantages:
Additional code is needed to increase the workload
Case demonstration
public abstract class Animal { public abstract void eat(); }
public interface BigFactory { //How to create a product Animal createAnimal(); }
public class Cat extends Animal { @Override public void eat() { System.out.println("Cats eat fish"); } }
//Create cat's factory public class CatFactroy implements BigFactory { @Override public Animal createAnimal() { return new Cat(); } }
public class Dog extends Animal { @Override public void eat() { System.out.println("Dogs eat bones"); } }
public class DogFactory implements BigFactory{ @Override public Animal createAnimal() { return new Dog(); } }
public class Tiger extends Animal{ @Override public void eat() { System.out.println("Tiger eats chicken"); } }
public class TigerFactory implements BigFactory{ @Override public Animal createAnimal() { return new Tiger(); } }
public class MyTest { public static void main(String[] args) { Animal an = new DogFactory().createAnimal(); an.eat(); an = new CatFactroy().createAnimal(); an.eat(); an = new TigerFactory().createAnimal(); an.eat(); } }
9. Design mode (lazy type of single mode) (Master)
A: Case demonstration: lazy style of single case mode
B: The difference between the hungry and the lazy
Lazy style of single design pattern
Starving Han style in development Lazy in interview Interview is to interview your two ideas: a: Thread safety thought b: Delay loading idea
Slovenly
public class Student { //Lazy writing: when you want to use this object, create it again private static Student student = null; //1. Private structure private Student() {} //2. Provide a static method to return an instance of the class for external use //Is it necessary to create an object to ensure this method in a multithreaded environment? //In addition, synchronized ensures that the use of multithreaded environment is also single column //th1 th2 public synchronized static Student getStudent() { if (student == null) { //th1 th2 student = new Student(); } return student; } } public class MyTest { public static void main(String[] args) { //Single column: ensure that there is only one class object in memory //Single example mode: lazy style, hungry style //1. Make the structure of this class private, and don't let it directly use the new object outside. // Student student = new Student(); Student student = Student.getStudent(); Student student1 = Student.getStudent(); System.out.println(student==student1); } }
Hungry Han style
public class Teacher {//Teacher.class //As soon as this class is loaded, I will create an object of this class private static Teacher teacher=new Teacher(); //Private structure private Teacher() { } public static Teacher getTeacher(){ return teacher; } } public class MyTest { public static void main(String[] args) { Teacher teacher = Teacher.getTeacher(); Teacher teacher1 = Teacher.getTeacher(); System.out.println(teacher); System.out.println(teacher1); System.out.println(teacher==teacher1); //In actual development, we use the starved Chinese style } }
10. Design pattern (Java code of singleton pattern embodies Runtime class) (understanding)
A:Runtime class overview
Each Java application has a Runtime class instance that enables the application to connect to its running environment. You can get the current Runtime through the getRuntime method.
The application cannot create its own instance of the Runtime class.
B: Case demonstration:
Public process exec (string command) / / execute Dos command
C: Check the source code of Runtime:
Discovery is the application of singleton pattern
public static void main(String[] args) throws IOException { // The Runtime class Java adopts the starved Chinese style of single column mode Runtime runtime = Runtime.getRuntime(); //Some DOS commands can be executed runtime.exec("calc"); runtime.exec("mspaint"); //Timed shutdown }
Timed shutdown
public class MyTest2 { public static void main(String[] args) throws ParseException { Timer timer = new Timer(); MyTask myTask = new MyTask(timer); timer.schedule(myTask,new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").parse("2020-06-07 11:35:00")); } } class MyTask extends TimerTask{ private Timer timer; public MyTask(Timer timer) { this.timer = timer; } @Override public void run() { //Timed shutdown try { Runtime runtime = Runtime.getRuntime(); runtime.exec("shutdown /s /t 0"); timer.cancel(); } catch (IOException e) { e.printStackTrace(); } } }
11. Design pattern (template design pattern overview and use) (understanding)
A: Requirement: calculate the execution time of a for loop
B: Template design pattern overview
The template method pattern is to define the skeleton of an algorithm and delay the specific algorithm to the subclass for implementation
C: Advantages and disadvantages
a: advantage: using the template method mode, while defining the algorithm skeleton, it can flexibly implement the specific algorithm to meet the user's flexible needs
b: disadvantage: if the algorithm skeleton is modified, the abstract class needs to be modified
D: Case demonstration: use of template design pattern
public abstract class CalcClass { public void calc(){ //Algorithm skeleton long start = System.currentTimeMillis(); calcMethod(); long end = System.currentTimeMillis(); System.out.println("Time consuming:"+(end-start)+"millisecond"); } /* private void forMethod() { for (int i = 0; i < 20000; i++) { System.out.println("aaa"); } } public void copyFile(){ System.out.println("Copy file '); }*/ public abstract void calcMethod(); }
public class CalcFor extends CalcClass { @Override public void calcMethod() { for (int i = 0; i < 5000; i++) { System.out.println("abc"); } } }
public class CopyFile extends CalcClass{ @Override public void calcMethod() { System.out.println("Copy file"); } }
public class MyTest { public static void main(String[] args) { //Single design mode //Time to calculate for loop // new CalcClass().calcFor(); CalcClass js = new CalcFor(); js.calc(); js=new CopyFile(); js.calc(); } }
12. Design mode (overview and use of decoration mode) (understanding)
A: Decoration mode overview:
The decoration mode is to use an instance of a subclass of the decorated class, and give the instance of this subclass to the decoration class on the client side. Is an alternative to inheritance
B: Advantages and disadvantages
a: advantages
Using decoration mode, you can provide more flexible functions of extending objects than inheritance. It can dynamically add the functions of objects,
And can combine these functions at will.
b: disadvantage: just because it can be combined at will, some unreasonable logic may appear.
C: Case demonstration: use of decoration mode
//Packaging class, to enhance the function of a class public class BZPhone implements Phone{ private Phone phone; //Which kind do you want to pack and pass it on public BZPhone(Phone phone) { this.phone = phone; } @Override public void call() { this.phone.call(); } }
public class GamePhone extends BZPhone { public GamePhone(Phone phone) { super(phone); } @Override public void call() { super.call(); System.out.println("Game functions"); } }
public class IPhone implements Phone{ public void call(){ System.out.println("phone"); } }
public class MusicPhone extends BZPhone{ public MusicPhone(Phone phone) { super(phone); } @Override public void call() { super.call(); System.out.println("The function of listening to songs"); } }
public interface Phone { void call(); }
public class VideoPhone extends BZPhone{ public VideoPhone(Phone phone) { super(phone); } @Override public void call() { super.call(); System.out.println("Functions of watching video"); } }
public class MyTest { public static void main(String[] args) { Phone iPhone = new IPhone(); iPhone.call(); System.out.println("====================="); MusicPhone musicPhone = new MusicPhone(iPhone); musicPhone.call(); System.out.println("===================="); VideoPhone videoPhone = new VideoPhone(iPhone); videoPhone.call(); System.out.println("============================="); VideoPhone videoPhone1 = new VideoPhone(new MusicPhone(iPhone)); videoPhone1.call(); System.out.println("============================"); MusicPhone musicPhone1 = new MusicPhone(new VideoPhone(iPhone)); musicPhone1.call(); System.out.println("===================="); GamePhone gamePhone = new GamePhone(new MusicPhone(iPhone)); gamePhone.call(); System.out.println("==========================="); GamePhone gamePhone1 = new GamePhone(new MusicPhone(new VideoPhone(iPhone))); gamePhone1.call(); } }
13. Design pattern (overview and use of observer pattern) (understanding)
A: Case: looking for headhunter and job
B: Observer = subscriber + publisher
Job seeker (registration method, cancellation method, release method)
public class Hunter { //Define two sets to hold job seekers and jobs private ArrayList<JobSeeker> jobSeekers=new ArrayList<>(); private ArrayList<Job> jobs = new ArrayList<>(); //Register for help public void addJobSeeker(JobSeeker jobSeeker){ jobSeekers.add(jobSeeker);} //Registered job public void addJob(Job job){ jobs.add(job); //Inform the job seeker when the position comes notifyJobSeeker(job);} private void notifyJobSeeker(Job job) { for (JobSeeker jobSeeker : jobSeekers) { System.out.println(jobSeeker.getName()+"Hello! Have a job:"+job.getJobName()+"salary:"+job.getSal()+"Welcome to the interview"); } } //cancellation public void removeJobSeeker(JobSeeker jobSeeker){ jobSeekers.remove(jobSeeker); } }
public class Job { private String jobName; private double sal; public Job() {} public Job(String jobName, double sal) { this.jobName = jobName; this.sal = sal; } public String getJobName() { } public void setJobName(String jobName) { this.jobName = jobName;} public double getSal() { return sal;} public void setSal(double sal) { this.sal = sal;} }
public class JobSeeker { private String name; public JobSeeker() { } public JobSeeker(String name) { this.name = name;} public String getName() { return name;} public void setName(String name) { this.name = name;} }
public class MyTest { public static void main(String[] args) { //Observer = subscriber + publisher JobSeeker zs = new JobSeeker("Zhang San"); JobSeeker ls= new JobSeeker("Li Si"); JobSeeker ww= new JobSeeker("Wang Wu"); //Register with headhunters Hunter hunter = new Hunter(); hunter.addJobSeeker(zs); hunter.addJobSeeker(ls); hunter.addJobSeeker(ww); Job job= new Job("Java Development Engineer", 8000); hunter.addJob(job); System.out.println("====================="); Job job2 = new Job("Front end development engineer", 18000); hunter.addJob(job2); System.out.println("========================"); //cancellation hunter.removeJobSeeker(ww); Job job3 = new Job("Operation and maintenance engineer", 5000); hunter.addJob(job3); } }
Knowledge review:
Copy multiple documents
public static void main(String[] args) throws IOException { //Make multiple copies of a document RandomAccessFile in = new RandomAccessFile("C:\\Users\\ShenMouMou\\Desktop\\Java And mode.pdf", "rw"); int len=0; byte[] bytes = new byte[1024 * 8]; for (int i = 0; i < 3; i++) { FileOutputStream out= new FileOutputStream(new File("C:\\Users\\ShenMouMou\\Desktop", i + "Design pattern.pdf")); while ((len=in.read(bytes))!=-1){ out.write(bytes,0,len); out.flush(); } //Set pointer to 0 position in.seek(0); out.close(); } in.close(); }
A:
Case demonstration
Requirement: I have a text file. I know that the data is in the form of key value pairs, but I don't know what the content is.
Please write a program to determine whether a key like "lisi" exists. If so, change its value to "100"
public static void main(String[] args) throws IOException { //Read profile Properties properties = new Properties(); properties.load(new FileReader("name.properties")); // System.out.println(properties); if (properties.containsKey("lisi")) { //Same key, value override properties.setProperty("lisi","100"); //Then write the modified data back to the text file properties.store(new FileWriter("name.properties"),null); System.out.println("Modification complete"); }else{ System.out.println("No, lisi Key of"); } }
Delete file
public static void main(String[] args) throws IOException { //chaiFen(); //merge File folder = new File("E:\\music"); File[] files = folder.listFiles(); Vector<InputStream> vector= new Vector<>(); for (File file : files) { if (file.length()<=1024*1024&&file.getName().endsWith(".mp3")) { FileInputStream in = new FileInputStream(file); vector.add(in); } } //SequenceInputStream(Enumeration < ? extends InputStream > e) Enumeration<InputStream> elements = vector.elements(); SequenceInputStream sequenceInputStream = new SequenceInputStream(elements); FileOutputStream out = new FileOutputStream(new File(folder,"merge.mp3")); byte[] bytes = new byte[1024 *8]; int len = 0; while ((len = sequenceInputStream.read(bytes)) != -1) { out.write(bytes, 0, len); } sequenceInputStream.close(); out.close(); //Finally, delete the fragmented small files for (File file : folder.listFiles()) { if (file.length() <= 1024 * 1024 && file.getName().endsWith(".mp3")) { file.delete(); } } } private static void chaiFen() throws IOException { //Split one document into multiple copies, one M each, and then merge them back File file = new File("E:\\music"); if (!file.exists()) { file.mkdirs(); } FileInputStream in = new FileInputStream("Xin Xiaoqi - understand.mp3"); //Position buffer size 1M byte[] bytes = new byte[1024 * 1024]; int len=0; int index=0; while ((len=in.read(bytes))!=-1){ index++; FileOutputStream out = new FileOutputStream(new File(file, index + ".mp3")); out.write(bytes,0,len); out.close(); } in.close(); }
Multiple threads copying files
public class MyTest { public static void main(String[] args) throws FileNotFoundException { //Multiple threads, copying a file together //Encapsulate source files File srcFile = new File("Xin Xiaoqi - understand.mp3"); //Get the total size of the file long totalLength = srcFile.length(); //totalLength=310; //Define the number of threads long threadNum =3; //The average size of bytes to be copied per thread of the computer long pj = totalLength / threadNum; //We have to calculate the start and end positions of the byte data copied by each thread for (long i = 0; i < threadNum; i++) { //0---100 //101---200 //201---300 long start = pj * i; long end = (i + 1) * pj - 1; //System.out.println("thread" + i + "start position:" + start + "end position:" + end); //Enable thread replication new CopyFileThread(start, end, srcFile, new File("E:\\understand.mp3")).start(); } //What if the size of the file is not enough to divide multiple threads equally? //My solution is, if it's not evenly distributed, I'm filling a thread and copying the rest if (totalLength % threadNum != 0) { System.out.println("Unequal distribution"); long start = threadNum * pj; long end = totalLength; //System.out.println("compensation thread" + "start position:" + start + "end position:" + end); new CopyFileThread(start, end, srcFile, new File("E:\\understand.mp3")).start(); } } } class CopyFileThread extends Thread { private long start; private long end; private RandomAccessFile in; private RandomAccessFile out; /** * @param start Start of replication per thread * @param end End of replication per thread * @param srcFile source file * @param targetFile Target file */ public CopyFileThread(long start, long end, File srcFile, File targetFile) throws FileNotFoundException { this.start = start; this.end = end; in = new RandomAccessFile(srcFile, "rw"); out = new RandomAccessFile(targetFile, "rw"); } @Override public void run() { try { //Set the location where each thread starts reading and writing in.seek(start); out.seek(start); int len = 0; byte[] bytes = new byte[1024*8]; //1 byte per cache //If you copy byte by byte, start < end is isolated //If your buffer is not a byte start < end logically isolated for the last time, it may be overwritten by multiple writes while (start < end && (len = in.read(bytes)) != -1) { start += len; out.write(bytes, 0, len); } in.close(); out.close(); } catch (IOException e) { e.printStackTrace(); } } }