目的:- 使用Java中的Blocking IO来构建多线程应用程序以下载文件。 请不要建议我使用Non-Blocking IO
,有人告诉我要使用此。
问题:-
我的代码在客户端计算机上工作正常,该客户端计算机下载服务器上托管的文件。但是,问题是我的服务器使用多个线程来播种该文件。在所有情况下,收到的文件都是确切的长度,但是文件似乎已损坏。就像,当我下载一个PDF文件时,文件页面被写到最后一半(意味着所有页面都充满了原始内容的一部分)。当我下载一首歌曲时,它会突然爆满,直到播放完这些杂音为止。
问题1:- 我应如何保持完美的流畅下载,以便文件正确播放/打开/读取?我应该在此解决由于多线程而引起的问题之类的技术?
我的代码:-
服务器多线程代码::::
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
,是否应该为每个线程创建一个单独的对象?如果在这种情况下建议如何使用它?
如果无法编写代码,请给我提供技术说明,答案中不必提及该代码。
正如其他人在评论中已经提到的那样,这是一种糟糕的方法,它不允许多个线程共享输入流并允许并发写入,这会导致文件损坏。
我在多线程分布式文件服务器项目中执行的一种方法是,我允许文件服务器的多线程执行,但只允许顺序执行线程。
我以这种方式进行编码,以确保线程以一种同步的方式(仅一种一种方式)访问输入流。这也没有在客户端破坏文件。而且,这在性能上也太惊人了。
注意,在对该答案采取任何措施之前:-
当时我对代码进行了基准测试,以确保我在答案中所说的确实对访问者/寻求者而言是最佳的。我认为这也是最佳情况,因为我有4个逻辑处理器(内核/
CPU),减少了多个线程的开销(尽管它们一次只能工作1个)。
人们会争辩说这是最糟糕的方法,或者是丑陋的方法,等等。但是我发现这对于文件服务器的播种非常有帮助。我的40 MB(大约)PDF文件 Linux Server [Intel(R) Core(TM) 2 Duo CPU E4600 @ 2.40GHz processor, CPU(s): 2]
平均在4-5次执行测试中平均需要33-34秒的时间被复制到文件客户端。而当我增加线程数(8-10个线程)时,性能下降大约需要36-38秒。当我拥有单线程服务器时,情况相同,在45-50秒内复制了同一文件。随着线程数量的增加,性能得以提高,并且在4至6个线程范围内非常有效。
但是,显然维护多个线程会产生开销,而且人们会以为单个线程可以获胜, 但是 令人 惊讶 的是,在4-6个线程的情况下,结果是最佳的。
因此,我的建议是按照代码中所示的那样,通过4-6个线程对输入流进行顺序访问来进行处理。这是最佳选择,请相信我,我也可以与其他人争论多线程开销,我发现这种开销在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();
如果队列已满,ArrayBlockingQueue将阻止生产者线程;如果队列为空,ArrayBlockingQueue将阻止消费者线程。 这种阻塞的概念是否与多线程的思想背道而驰?如果我有一个“主”线程,并假设我想将所有“日志记录”活动委托给另一个线程。因此,基本上在我的主线程内,我创建了一个Runnable来记录输出,并将其放在ArrayBlockingQueue上。这样做的全部目的是让“主”线
在Java中,线程可以有不同的状态: 新建、可运行、阻止、等待、定时等待、终止 但是,当线程被IO阻塞时,其状态为“RUNNABLE”。我如何判断它是否被IO阻止?
我有4-5个工作线程处理大型消息队列。我还有另一段代码,它使用2-3个worker运行。我想在处理大型消息队列时阻止所有其他工作者。 我正在使用JDK6和Jms 编辑: 队列进程工作者从未终止。当没有消息时,它们阻塞队列。这些工作者由执行器线程池管理,如果我使用读写锁,其中一个工作者也会被阻塞。此外,如果使用循环屏障,那么我必须终止线程,以便重新传递阻塞的第二个进程。由于工作者是由线程池管理的,所
本文向大家介绍详解Java多线程编程中CountDownLatch阻塞线程的方法,包括了详解Java多线程编程中CountDownLatch阻塞线程的方法的使用技巧和注意事项,需要的朋友参考一下 直译过来就是倒计数(CountDown)门闩(Latch)。倒计数不用说,门闩的意思顾名思义就是阻止前进。在这里就是指 CountDownLatch.await() 方法在倒计数为0之前会阻塞当前线程。
问题内容: 我有一个在后台运行的线程正在以阻塞方式从输入设备读取事件,现在当我退出应用程序时,我想正确清理线程,但是我不能只运行pthread_join(),因为该线程由于IO阻塞而永远不会退出。 我如何正确解决这种情况?我应该发送一个pthread_kill(theard,SIGIORM)还是一个pthread_kill(theard,SIGALRM)来中断该块?那两个信号是否正确?还是有另一种
非阻塞 IO 仅对在 Servlet 和 Filter(2.3.3.3节定义的,“异步处理”)中的异步请求处理和升级处理(2.3.3.5节定义的,“升级处理”)有效。否则,当调用 ServletInputStream.setReadListener 或ServletOutputStream.setWriteListener 方法时将抛出IllegalStateException。为了支持在 Ser