我使用多个线程将文件上传到服务器。 Java Applet负责显示UI。最初我使用ThreadPoolExecutor& amp;为他们分配5个文件。每次上传后,我都会收到服务器的通知。当一个线程完成执行时,另一个新线程被分配一个文件,直到所有文件都被上传到服务器。
基本代码结构如下:
I>从Java Applet调用方法startUpload(),它负责处理上载功能。
class Upload extends Runnable{
...............................
..............................
public void startUpload() {
............................... //other initialisations done
int waitTime = 500;
Random random = new Random();
ExecutorService executor = new ThreadPoolExecutor(5, 5, 50000L, TimeUnit.MILLISECONDS, new ArrayBlockingQueue<Runnable>(300));
while (it.hasNext()) {
int time = random.nextInt(1000);
waitTime += time;
newFile = new File((String) it.next());
executor.execute(new Runnable() {
@Override
public void run() {
try{
Thread.sleep(wait);
}
catch(Exception e){
}
processFile1(newFile);
}
});
}
try {
Thread.sleep(waitTime);
executor.shutdown();
executor.awaitTermination(waitTime, TimeUnit.MILLISECONDS);
} catch (Exception e) {
}
}
}
我目前面临的问题。
I&GT; UI仅在上载所有文件时更新。在中间阶段,UI处于挂起状态。似乎EDT将进入封锁状态。
当我使用Thread类,notify / sleep实现相同的功能时,UI呈现的相同代码工作正常。我将代码更改为ThreadPoolExecutor,因为我在一篇博客/文章中看到它是从Java ver 5.0实现多线程的更好方法。
II&GT;我注意到ThreadPoolExecutor的另一件事,当我上传大小为1KB的多个文件(用于测试目的)时,如果我从上面的代码中删除所有的wait(),则以下行分配一个新文件,但同一个文件是每次都由多个线程上传。
newFile = new File((String)it.next());
但是在使用run()添加sleep()时,多个线程会将不同的文件上传到服务器。
上述代码是否存在任何实施问题?
答案 0 :(得分:2)
问题1:newFile
是(静态?)字段而不是局部变量。
您想要确保每个循环的newFile
的本地捕获不同。因此,它看起来应该更像:
while(it.hasNext()) {
final File newFile = new File((String) it.next());
executor.execute(new Runnable() {
@Override
public void run() {
processFile1(newFile); // Local only to this iteration of the loop.
}
}
}
您的代码全部包含在Runnable
实例中。你能让我们知道调用Thread的是什么吗?如果它在EDT上,则可以解释UI锁定的原因。
一个小问题是你的迭代器缺乏泛型。从理论上讲,你应该迭代一串字符串:
Collection<String> listOfFiles = ...
Iterator<String> it = listOfFiles.iterator();
while(it.hasNext()) {
String filename = it.next(); // No cast necessary
}
答案 1 :(得分:1)
UI正在挂起,因为您阻止了EDT线程。这段代码是罪魁祸首:
try {
Thread.sleep(waitTime);
executor.shutdown();
executor.awaitTermination(waitTime, TimeUnit.MILLISECONDS);
} catch (Exception e) {
}
ExecutorService
的想法是你在初始化期间创建它一次,并且永远不要关闭它直到程序准备好退出。对此的习语可能是:
ExecutorService executor = Executors.newFixedThreadPool(5);
Runtime.getRuntime().addShutdownHook(new Thread() {
public void run() {
executor.shutdown();
}
});
正如@ Bringer128所提到的,第二个问题是由于您正在更改静态或成员变量的值而未将File
引用分配给新位置。如果代码是正确的,我们希望看到newFile
声明为final File newFile
,因为非最终的局部变量可能不会在内部类中被引用。