Java 如果前一个线程没有';没有完成

Java 如果前一个线程没有';没有完成,java,multithreading,runnable,Java,Multithreading,Runnable,我正在尝试编写一个简单的视频操纵器,因此每秒有几次我需要启动一个新线程(目前正在实现Runnable)要处理当前帧,但我不能保证每个线程需要多长时间才能完成,因此我希望将一次可以运行的线程数限制为计算机上的处理器数: Runtime runtime = Runtime.getRuntime(); int nP = runtime.availableProcessors(); 但我需要保证创建的所有线程都是按顺序运行的,所以不会丢弃任何帧 我还想向用户展示完成处理需要多长时间,这取决于他们取

我正在尝试编写一个简单的视频操纵器,因此每秒有几次我需要启动一个新线程(目前正在实现Runnable)要处理当前帧,但我不能保证每个线程需要多长时间才能完成,因此我希望将一次可以运行的线程数限制为计算机上的处理器数:

Runtime runtime = Runtime.getRuntime();
int nP = runtime.availableProcessors();  
但我需要保证创建的所有线程都是按顺序运行的,所以不会丢弃任何帧

我还想向用户展示完成处理需要多长时间,这取决于他们取消作业时剩余的线程数,这样他们就不会得到没有预告片的视频文件

使用futureTask、Exector或ExecutorService的任何组合都可以实现这一点吗

谢谢

编辑:

嗨,伙计们,对不起,是的,措辞很糟糕。所以我实际上要做的是获取帧,执行一些图像处理,然后将编辑的片段保存回一个新文件。在播放过程中,我正在执行此操作,因此当计时器调用每一帧时,会对其进行操作,然后计时器会启动一个线程以尽可能快地处理图像,但这取决于这次执行的操作次数

然后,我想确保,如果处理时间长于间隔,则仅使用最大有效线程数进行处理,并且在达到此限制后创建的任何线程仍将被处理,而不会被丢弃或垃圾收集

阅读了前3条评论后,我发现这可能是一种效率较低的方法,我想只有一个线程来保持UI的响应性是可行的,但我不确定如何在不使用大量列表的情况下继续将图像添加到线程中进行处理。我想大概是这样的:

在主要类别中:

Timer actionPerformed {
    List.add(decodedImage);
}
在runnable类中:

run() {
   while( timer.isRunning() ) {
     if( runCount >= list.size()-1 ) {
        try {
          Thread.sleep(500);
        } catch() {
             /* Catchy stuff */
        }
     } else {
        BufferedImage toProcess = list.get(runCount);
        /* Do Processing here */
        writeImageToStream();
        list.remove(runCount);
        runCount++;
     }
   }
}
这是正确的吗

编辑2:

这就是我到目前为止所做的:

public class timerEncode {

     private long startTime;

     ActionListener goAction = new ActionListener() {
         public void actionPerformed( ActionEvent evt ) {
             BufferedImage decoded = getNextImage();
             long write_time = System.nanoTime();
             new doImages(decoded, write_time).run();
         }        
     };
     Timer goTimer = new Timer(40,goAction);

     private BufferedImage getNextImage() {
        /* Does inconsequential stuff to retrieve image from the stream*/
     }

     private void recBtnActionPerformed(java.awt.event.ActionEvent evt) {                                       
        startTime = System.nanoTime();
        goTimer.start();
     }

     private class doImages implements Runnable {
        final BufferedImage image;
        final long write_time;

        public doImages(BufferedImage image, long write_time) {
           this.image = image;
           this.write_time = write_time;
        }

        public void run() {
            BufferedImage out = toXuggleType(image, BufferedImage.TYPE_3BYTE_BGR);
            /* Other time consuming processy stuff goes here */
            /* Encode the frame to a video stream */
            writer.encodeVideo(0,out,write_time-startTime, TimeUnit.NANOSECONDS);
        }

        private BufferedImage toType(BufferedImage source, int type) {
            if( source.getType() != type ) {
                BufferedImage temp = new BufferedImage(source.getWidth(),source.getHeight(),type);
                temp.getGraphics().drawImage(source, 0, 0, null);
                source = temp;
            }
            return source;
        }
    }

}

当图像处理很简单时,这很好,但很快就会遇到数十个并发线程试图执行它们的任务,因为它变得有点复杂,因此我问如何限制并发线程数而不删除任何线程。我不确定顺序在这种情况下是否特别重要,因为我认为不按顺序写入帧会将它们放在正确的位置,因为每个帧都指定了写入时间,但这需要测试。

连续启动线程是个坏主意-这对性能有很大影响。你想要的是一个线程池和一堆要做的工作(可运行程序)。如果您创建一个大小=处理器数量的线程池,并且只将帧(作为作业)添加到作业队列中,那么您的线程将能够高效地按顺序处理队列中的所有帧

连续地启动线程是个坏主意-这会对性能造成很大影响。你想要的是一个线程池和一堆要做的工作(可运行程序)。如果您创建一个大小=处理器数量的线程池,并且只将帧(作为作业)添加到作业队列中,那么您的线程将能够高效地按顺序处理队列中的所有帧

[查看历史记录了解以前的回复]

我知道现在发生了什么。我不完全确定
定时器
ActionListeners
是如何工作的(如果前一个调用在另一个调用到达时没有完成,会发生什么情况),但似乎您实际上并没有同时运行
doImages
对象-要同时运行
Runnable
对象,您需要执行
Thread t=new Thread(runnableObject);t、 start()
如果您只调用
run()
方法,它将按顺序执行(与任何其他方法调用一样),因此您的
actionPerformed()
方法在
run()
执行之前不会完成。我不确定这是否会阻止(或延迟)处理其他
ActionEvents

正如其他人所建议的,要限制线程数,应该使用
threadpoolexecutor
对象。这将使您的
actionPerformed()
方法快速返回,同时运行
doImages
对象,并确保不会在队列中使用太多线程。你所需要做的就是替换
新的doImages(解码,写入时间)threadPool.execute(新的doImages(已解码,写入时间))


至于如何监控流程,您可以使用
ThreadPoolExcecutor
getQueue()
方法检索和检查队列的大小,以查看有多少帧等待处理。

[有关以前的响应,请参阅历史记录]

我知道现在发生了什么。我不完全确定
定时器
ActionListeners
是如何工作的(如果前一个调用在另一个调用到达时没有完成,会发生什么情况),但似乎您实际上并没有同时运行
doImages
对象-要同时运行
Runnable
对象,您需要执行
Thread t=new Thread(runnableObject);t、 start()
如果您只调用
run()
方法,它将按顺序执行(与任何其他方法调用一样),因此您的
actionPerformed()
方法在
run()
执行之前不会完成。我不确定这是否会阻止(或延迟)处理其他
ActionEvents

正如其他人所建议的,要限制线程数,应该使用
threadpoolexecutor
对象。这将使您的
actionPerformed()
方法快速返回,同时运行
doImages
对象,并确保不会在队列中使用太多线程。你所需要做的就是替换
新的doImages(解码,写入时间)threadPool.execute(新的doImages(已解码,写入时间))

至于怎么做呢
// Create a thread pool with the given concurrency level
ExecutorService executor = Executors.newFixedThreadPool(Runtime.availableProcessors);

// Submit all tasks to the pool, storing the futures for further reference
// The ? here should be the class of object returned by your Callables
List<Future<?>> futures = new ArrayList<Future<?>>(NUM_FRAMES);
for (int i = 0; i < NUM_FRAMES; i++)
{
    futures.add(executor.submit(createCallableForFrame(i)));
}

// Combine results using future.get()
// e.g. do something with frames 2 and 3:
mergeFrames(futures.get(2).get(), futures.get(3).get());

// In practice you'd probably iterate through the Futures but it's your call!