使用Blocking IO进行multithreading会破坏Java中的文件

目的: –使用Java中的Blocking IO构建multithreading应用程序以下载文件。 请不要建议我使用Non-Blocking IO ,我被告知要使用这个。

问题: –我的代码在下载托管在服务器上的文件的客户端计算机上正常工作。 但是,问题是我的服务器使用多个线程播种文件。 在所有情况下,收到的文件都是精确的长度,但文件显示已损坏。 就像,当我下载PDF文件时,文件页面被写入到最后一半(意味着所有页面都填充了原始文件的部分内容)。 当我下载一首歌时,它会在整个过程中爆发并播放到那些噪音位。

问题1: –如何保持完美平滑的下载,以便文件正常播放/打开/读取? 我应该在这里解决因multithreading引起的问题。

我的代码: –

服务器multithreading代码::::

import java.io.BufferedInputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; public class FileServer extends UnicastRemoteObject implements FileServerInitialise{ private String file=""; public FileServer() throws RemoteException{ super(); } public void setFile(String f){ file=f; //System.out.println("Length in setFile = "+f); } @Override public boolean login(FileClientInitialise fci) throws RemoteException { try { InputStream is = new BufferedInputStream(new FileInputStream(file)); long len = new File(file).length(); System.out.println("Length of File = "+len); WorkerThread wt1=new WorkerThread(0,len/2,fci,is,file); wt1.setName("Worker Thread 1"); WorkerThread wt2=new WorkerThread(len/2+1,2*len/2,fci,is,file); wt2.setName("Worker Thread 2"); //WorkerThread wt3=new WorkerThread(2*len/4+1,3*len/4,fci,is,file); //wt3.setName("Worker Thread 3"); //WorkerThread wt4=new WorkerThread(3*len/4+1,len,fci,is,file); //wt4.setName("Worker Thread 4"); wt1.start(); wt2.start(); //wt3.start(); //wt4.start(); wt1.join(); wt2.join(); //wt3.join(); //wt4.join(); return true; } catch (InterruptedException iex) { iex.getMessage(); return false; } 

客户端下载代码::::

 import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.RandomAccessFile; public class FileClient implements FileClientInitialise { public static int count = 1; public static File f; public static FileOutputStream fos; public static RandomAccessFile raf; public static long pointer; public FileClient (String filename) throws RemoteException, IOException { super(); FileClient.f= new File(filename); FileClient.fos = new FileOutputStream(f, true); //FileClient.raf= new RandomAccessFile(f,"rwd"); FileClient.pointer=0; } @Override public boolean sendData(String filename, byte[] data, int len, String threadName) throws RemoteException{ try{ FileClient.fos.write(data,0,len); FileClient.fos.flush(); //FileClient.raf.seek(FileClient.pointer); //FileClient.raf.write(data,0, len); //FileClient.pointer=raf.getFilePointer(); System.out.println("Done writing data..."); //fos.close(); return true; }catch(Exception e){ e.getMessage(); return false; } } } 

问题2: –另外,我应该使用RandomAccessFile来实现相同的目标吗? 会更好吗? 我检查了它,它的工作速度非常慢(几乎慢了10倍)。 而且,如果我要使用RandomAccessFile ,我应该为每个线程创建一个单独的对象吗? 如果在这种情况下建议,我应该如何使用它?

如果代码不可用,请给我一个技术说明,代码没有必要在答案中提及。

正如其他人在评论中已经提到的那样,这是一种很糟糕的方法,允许多个线程共享输入流并允许并发写入,这会导致文件损坏。

我在multithreading分布式文件服务器项目中执行的一种方法是,我允许文件服务器的multithreading执行,但只允许顺序线程执行。

我以这样的方式编码,以确保线程以同步的方式访问输入流,只有一种方式。 这并没有在客户端破坏文件。 而且,这太令人惊讶了。

注意,在对此答案采取任何行动之前: –

我当时对代码进行了基准测试,以确保我在此答案中所述的内容对于访问者/搜索者来说确实是最佳的。 我认为这也是最佳情况,因为我有4个逻辑处理器(内核/ CPU),这减少了多个线程的开销(尽管它们一次只能工作1个)。

人们会认为这是最糟糕的方法,或者是丑陋的方法等。 但我发现这在文件服务器播种中非常有用。 Linux Server [Intel(R) Core(TM) 2 Duo CPU E4600 @ 2.40GHz processor, CPU(s): 2]上的40 MB(大约)PDF文件Linux Server [Intel(R) Core(TM) 2 Duo CPU E4600 @ 2.40GHz processor, CPU(s): 2]在近33-34秒内被复制到文件客户端平均4-5次执行测试。 然而,当我增加线程数(8-10个线程)时,性能下降大约需要36-38秒。 我有单线程服务器的情况也是如此,其中在45-50秒内复制了相同的文件。 随着线程数量的增加,性能得到改善,并且在4-6线程范围内有效。

虽然,显然会有维持这么multithreading的开销,人们会认为单个线程可以赢, 但是,令人惊讶的是,结果在4-6线程的情况下是最佳的。

所以,我的建议是通过4-6个线程执行输入流的顺序访问来按代码所示继续进行。 这是最佳的,相信我,我也可以与其他人争论multithreading的过头,我发现在4-6线程的情况下最佳。

对于您的代码,我建议进行以下更改: –

 InputStream is = new BufferedInputStream(new FileInputStream(file)); long len = new File(file).length(); System.out.println("Length of File = "+len); int numOFThreads=4; WorkerThread wt1=new WorkerThread(0,len/numOFThreads,fci,is,file); wt1.setName("Worker Thread 1"); WorkerThread wt2=new WorkerThread(len/numOFThreads+1,2*len/numOFThreads,fci,is,file); wt2.setName("Worker Thread 2"); WorkerThread wt3=new WorkerThread(2*len/numOFThreads+1,3*len/numOFThreads,fci,is,file); wt3.setName("Worker Thread 3"); WorkerThread wt4=new WorkerThread(3*len/numOFThreads+1,4*len/numOFThreads,fci,is,file); wt4.setName("Worker Thread 4"); wt1.start(); wt1.join(); wt2.start(); wt2.join(); wt3.start(); wt3.join(); wt4.start(); wt4.join();