首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用阻塞IO的多线程在Java中损坏文件

使用阻塞IO的多线程在Java中损坏文件
EN

Stack Overflow用户
提问于 2015-06-17 07:31:08
回答 1查看 654关注 0票数 0

AIM :-用于构建多线程应用程序,使用阻塞IO在Java中下载文件。请不要建议我使用非阻塞IO,我被告知要使用这个。

问题:-我的代码在下载服务器上的文件的客户端机器上运行良好。但是,问题是my使用多个线程启动文件。在所有情况下,收到的文件都具有精确的长度,但文件似乎已损坏。比如,当我下载一个PDF文件时,文件页被写到最后一个文件的一半(意味着所有的页面都填充了原始文件的部分内容)。当我下载一首歌的时候,它会一直播放,直到最后播放那些噪音片段。

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

我的守则:-

服务器多线程代码:

代码语言:javascript
复制
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;
        } 

客户端下载代码:

代码语言:javascript
复制
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,应该为每个线程创建一个单独的对象吗?如果在这种情况下,我应该如何使用它?

如果代码是不可能的,请给我一个技术描述,代码没有必要在答案中提到。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2015-06-18 15:06:42

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

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

我以这种方式编写代码,以确保线程以同步的方式访问输入流,而不是一个一个地访问输入流。这在客户端也没有损坏文件。而且,这是非常有效的表现。

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

当时我对守则进行了基准测试,以确保我在这个答案中所述的,对访客/寻求者来说,确实是最佳的。我认为这是最好的情况,因为我有4个逻辑处理器(核心/CPU),这减少了多个线程的开销(尽管它们一次工作一个)。

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

不过,维护这么多线程显然会带来开销,人们会认为一个线程可以获胜,,但令人惊讶的是,在4-6个线程的情况下,的结果是最佳的。

因此,我的建议是按照代码中所示,通过4-6个线程对输入流执行顺序访问。这是最优的,相信我,我也可以和其他人争论多线程过头问题,我发现在4-6个线程的情况下,这是最优的。

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

代码语言:javascript
复制
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();
票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/30885037

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档