使用Blocking IO进行多线程处理在Java中破坏文件 [英] Multithreading using Blocking IO corrupts file in Java

查看:143
本文介绍了使用Blocking IO进行多线程处理在Java中破坏文件的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

AIM:使用Java中的Blocking IO构建多线程应用程序以下载文件。 请不要建议我使用非封锁IO ,我已被告知要使用此封邮件。



问题: 我的代码在下载服务器上托管的文件的客户端计算机上正常工作。但是,问题是我的服务器种子的文件使用多线程。在所有情况下,接收的文件具有确切的长度,但是,文件显示已损坏。例如,当我下载PDF文件时,文件页面被中途写入最后一个(意味着所有页面都填充了原始文件的部分内容)。当我下载一首歌曲,它是爆炸整个&

问题1: - 我应该如何保持完美的平滑下载,以便文件播放/打开/读取正确?我应该在这里解决什么技术问题,因为多线程应该解决?



我的代码: -



服务器多线程code ::::

  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(\" 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(File 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;
}
}
}

- 此外,我应该使用 RandomAccessFile 实现相同吗?会更好吗?我检查了它,它的工作非常缓慢(几乎慢10倍)。如果我使用 RandomAccessFile ,我应该为每个线程创建一个单独的对象吗?如果在这种情况下建议,我应该如何使用它?



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

解决方案

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



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



我以这种方式编码,以确保线程以同步方式访问输入流,只有一个方式。这没有损坏的文件在客户端。

注意,在对此回答执行任何操作之前: - / p>

我当时做了代码的基准测试,以确保我在这个答案中所说的对访问者/寻求者来说是最佳的。我相信这是最佳的情况也是因为我有4个逻辑处理器(核心/ CPU),减少了多线程的开销(虽然他们都工作1在一个时间)。



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



然而,显然会有维护这么多线程,人们会认为单线程可以赢,但是,令人惊讶地,的结果是4-6线程的情况下是最佳的。



因此,我的建议是通过4-6个线程执行输入流的顺序访问,如代码所示继续。这是最好的,相信我,我可以与其他人争论多线程overheading我发现最佳的情况下4-6线程。



对于你的代码,我建议以下更改: -

  InputStream is = new BufferedInputStream(new FileInputStream(file)); 
long len = new File(file).length();
System.out.println(File 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();


AIM :- TO build a multithreading application using Blocking IO in Java to download a file. Please don't suggest me to use Non-Blocking IO, I have been told to use this one.

Issue :- My code works fine on a client machine which downloads a file hosted on a server. But, the issue is my Server seeds the file using multiple threads. In all the cases, the file received is of exact length,but, the file appears corrupted. Like, when I download a PDF file, the file pages are halfway written to the last(means all pages are filled with partial content of the original). When I download a song, it is bursted throughout & plays till last with those noise bits.

Question 1 :- How should I maintain the perfect smooth downloading so that the file plays/opens/reads properly? What technique like issues because of multithreading should I resolve here?

My Code :-

Server Multi-threading code ::::

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;
        } 

Client Downloading code ::::

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;
}
}
}

Question 2 :- Also, should I use RandomAccessFile to achieve the same? Would it be more better? I checked it and it works very slow(almost 10 times slower). And, if I were to use RandomAccessFile, should I create a separate object for each thread? How should I use it, if advised in this case?

If code isn't possible, please give me a technical description, the code isn't necessary to be mentioned in the answer.

解决方案

As others have already mentioned in the comments, this is a poor approach to allow input streams to be shared by multiple threads and allow concurrent writing, which results in corruption of file.

One approach which I performed in my multithreaded distributed file-server project was that I allowed the multi-threaded execution of the file-server, but only sequential thread execution.

I coded in such a way to ensure that the threads access the input-stream in a synchronised way,only one by one manner. This didn't corrupt the file either at the client side. And, this was performance effective too amazingly.

NOTE, before taking any action on this answer :-

I did benchmarking of codes at that time to ensure that what I have stated in this answer really is optimal for the visitors/seekers. This I believe was the optimal case also because I had 4 logical processors(cores/CPU) which reduced the overhead of multiple threads(though they all working 1 at a time).

People would argue that this is worst approach,OR an ugly approach,etc. But I found this very helpful in the file-server seeding. My 40 MB(approximately) of PDF file on Linux Server [Intel(R) Core(TM) 2 Duo CPU E4600 @ 2.40GHz processor, CPU(s): 2] was copied to the file-client in almost 33-34 seconds on an average in 4-5 execution tests. Whereas, when I increased the number of threads(8-10 threads), the performance decreased taking about 36-38 seconds. Same was the case when I had the single-threaded server, in which the same file was copied in 45-50 seconds. With increase in the number of threads, the performance improved and it was efficient in the range of 4-6 threads.

Though, there would obviously be overhead of maintaining so many threads, and people would have thought that a single thread could win, BUT, SURPRISINGLY, the result was optimal in case of 4-6 threads.

So, my suggestion is to proceed as shown in the code by performing sequential accessing of input-streams by 4-6 threads. This is optimal, and believe me, I can argue with others too about multi-threads overheading which I found optimal in case of 4-6 threads.

For your code, I'd suggest the following change :-

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();

这篇关于使用Blocking IO进行多线程处理在Java中破坏文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆