如何在Java中设置线程限制

如何在Java中设置线程限制,java,multithreading,limit,Java,Multithreading,Limit,假设我有1000个文件要读,由于一些限制,我想并行读最多5个文件。而且,一旦其中一个完成了,我希望一个新的开始 我有一个拥有文件列表的主函数,每当一个线程完成时,我都会尝试更改计数器。但它不起作用 有什么建议吗 以下是主要的功能循环 for (final File filename : folder.listFiles()) { Object lock1 = new Object(); new myThread(filename, lock1).start(); cou

假设我有1000个文件要读,由于一些限制,我想并行读最多5个文件。而且,一旦其中一个完成了,我希望一个新的开始

我有一个拥有文件列表的主函数,每当一个线程完成时,我都会尝试更改计数器。但它不起作用

有什么建议吗

以下是主要的功能循环

for (final File filename : folder.listFiles()) {

    Object lock1 = new Object();
    new myThread(filename, lock1).start();
    counter++;
    while (counter > 5);
}

无论您使用什么方法创建新线程,递增一个全局计数器,在线程创建周围添加一个条件语句,如果达到限制,则不创建新线程,可能将文件推送到队列(列表?),然后您可以在创建线程后添加另一个条件语句,如果队列中有项目,请先处理这些项目。

像这样生成线程不是好办法。使用执行器服务,并将池指定为5。将所有文件放在类似于
BlockingQueue
或另一个线程安全集合中,所有正在执行的文件都可以随意
poll()

public class ThreadReader {

    public static void main(String[] args) {
        File f = null;//folder
        final BlockingQueue<File> queue = new ArrayBlockingQueue<File>(1000);
        for(File kid : f.listFiles()){
            queue.add(kid);
        }

        ExecutorService pool = Executors.newFixedThreadPool(5);

        for(int i = 1; i <= 5; i++){
            Runnable r = new Runnable(){
                public void run() {
                    File workFile = null;
                    while((workFile = queue.poll()) != null){
                        //work on the file.
                    }
                }
            };
            pool.execute(r);
        }
    }
}
公共类线程读取器{
公共静态void main(字符串[]args){
文件f=null;//文件夹
最终阻塞队列=新的ArrayBlockingQueue(1000);
对于(文件kid:f.listFiles()){
添加(kid);
}
ExecutorService池=Executors.newFixedThreadPool(5);

对于(inti=1;iKylar的答案中的方法是正确的。使用Java类库提供的executor类,而不是从头开始实现线程池(很糟糕)


但是我认为讨论你的问题中的代码以及为什么它不起作用可能是有用的。(我已经尽我所能填写了你遗漏的部分…)

好的,那么这有什么问题?为什么不起作用

第一个问题是,在
main
中,您正在读取和写入
计数器
,而没有进行任何同步。我假设它也正在由工作线程更新-否则代码就没有意义。因此,这意味着主线程很有可能看不到由e子线程。换句话说,
while(counter>5);
可能是一个无限循环。(事实上,这很有可能。JIT编译器可以生成代码,其中
counter>5
只测试前一个
counter++;
语句后寄存器中剩余的
counter
的值


第二个问题是,您的
while(counter>5);
循环对资源的浪费令人难以置信。您告诉JVM轮询一个变量……它可能每秒轮询数十亿次……运行一个处理器(核心)全力以赴。你不应该这样做。如果你打算用低级原语实现这类东西,你应该使用Java的
Object.wait()
Object.notify()
方法;例如,主线程等待,每个工作线程通知。

你可以使用ExecutorService作为线程池和队列

ExecutorService pool = Executors.newFixedThreadPool(5);
File f = new File(args[0]);

for (final File kid : f.listFiles()) {
    pool.execute(new Runnable() {
        @Override
        public void run() {
            process(kid);
        }
    });
}
pool.shutdown();
// wait for them to finish for up to one minute.
pool.awaitTermination(1, TimeUnit.MINUTES);

+1.重新发明轮子毫无意义。不过,我想你指的是ThreadPoolExecutor。据我所知,J2SE中没有ExecutorPool。Jdk5以后,有很多用于线程处理的inbuit类。正如kylar建议的那样,使用ExecutorPool更好。是的,实际上我指的是ExecutorService。修复并添加了超级粗糙的源代码,以提供gist.this与使用Runnable创建5个线程没有什么不同。这太过分了。您不需要队列和ExecutorService。因为ExecutorService是一个固定的线程池,您可以将所有任务提交给它,它们将一次运行5个线程,直到全部完成。不需要队列。
ExecutorService pool = Executors.newFixedThreadPool(5);
File f = new File(args[0]);

for (final File kid : f.listFiles()) {
    pool.execute(new Runnable() {
        @Override
        public void run() {
            process(kid);
        }
    });
}
pool.shutdown();
// wait for them to finish for up to one minute.
pool.awaitTermination(1, TimeUnit.MINUTES);