ThreadPoolExecutor的实现问题

时间:2011-11-10 05:39:54

标签: java multithreading applet

我使用多个线程将文件上传到服务器。 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()时,多个线程会将不同的文件上传到服务器。

上述代码是否存在任何实施问题?

2 个答案:

答案 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,因为非最终的局部变量可能不会在内部类中被引用。