简体   繁体   English

同步线程池ExecutorService

[英]Synchronization Thread Pool ExecutorService

this is my first time using thread pools and I dont quite understand how the executorservice works. 这是我第一次使用线程池,我不太了解executorservice的工作方式。 I put watermarks over an image and merge them onto an empty picture. 我将水印放在图像上,然后将它们合并到一张空白图片上。 But even if i only use one thread it will still only draw half. 但是即使我只使用一个线程,它也只会画一半。

This is my WorkerThread class : 这是我的WorkerThread类

public class WorkerThread implements Runnable {

    BufferedImage source;
    BufferedImage toDraw;
    int x;
    int y;
    BufferedImage target;
    ParallelWatermarkFilter pf;

    public WorkerThread(BufferedImage source, BufferedImage toDraw, int x, int y, BufferedImage target){
        this.source = source;
        this.toDraw = toDraw;
        this.x = x;
        this.y = y;
        this.target = target;
        pf = new ParallelWatermarkFilter(source, 5);
    }

    @Override
    public void run() {
        pf.mergeImages(source, toDraw, x, y, target);
    }
}

And this is is how i use the ExecutorService in my FilterClass : 这就是我在FilterClass中使用ExecutorService的方式

    public BufferedImage apply(BufferedImage input) {

        ExecutorService threadpool = Executors.newFixedThreadPool(numThreads);

                for (int w = 0; w < imgWidth; w += watermarkWidth) {
      for (int h = 0; h < imgHeight; h += watermarkHeight) {
            Runnable worker = new WorkerThread(input, watermark, w, h, result);
            System.out.println("WIDTH: " + w + "   HEIGHT: " + h);
            threadpool.execute(worker);
      }
    }

    threadpool.shutdown();

Do the threads not wait until one thread is done ? 线程是否不等到一个线程完成?

The thing ThreadPoolExecutor shutdown and task execution/draining work queue/taking from work queue is racy. ThreadPoolExecutor关机和任务执行/排空工作队列/从工作队列中取出是一件ThreadPoolExecutor的事。 So you cannot rely on thread interruptiong mechanism or something else. 因此,您不能依赖线程中断机制或其他方法。 All you are guaranteed with is: 您所能保证的是:

Initiates an orderly shutdown in which previously submitted tasks are executed, but no new tasks will be accepted. 启动有序关闭,在该关闭中执行先前提交的任务,但不接受任何新任务。 Invocation has no additional effect if already shut down. 如果已关闭,则调用不会产生任何其他影响。

This method does not wait for previously submitted tasks to complete execution. 此方法不等待先前提交的任务完成执行。

To dig a bit deeper into the ThreadPoolExecutor implementation lets take a look at the main execution method: 为了更深入地了解ThreadPoolExecutor实现,让我们看一下主要的执行方法:

final void runWorker(Worker w) {
    Thread wt = Thread.currentThread();
    Runnable task = w.firstTask;
    w.firstTask = null;
    w.unlock(); // allow interrupts
    boolean completedAbruptly = true;
    try {
        while (task != null || (task = getTask()) != null) {
            w.lock();
            // If pool is stopping, ensure thread is interrupted;
            // if not, ensure thread is not interrupted.  This
            // requires a recheck in second case to deal with
            // shutdownNow race while clearing interrupt
            if ((runStateAtLeast(ctl.get(), STOP) ||
                 (Thread.interrupted() &&
                  runStateAtLeast(ctl.get(), STOP))) &&
                !wt.isInterrupted())
                wt.interrupt();
            try {
                beforeExecute(wt, task);
                Throwable thrown = null;
                try {
                    task.run();
                } catch (RuntimeException x) {
                    thrown = x; throw x;
                } catch (Error x) {
                    thrown = x; throw x;
                } catch (Throwable x) {
                    thrown = x; throw new Error(x);
                } finally {
                    afterExecute(task, thrown);
                }
            } finally {
                task = null;
                w.completedTasks++;
                w.unlock();
            }
        }
        completedAbruptly = false;
    } finally {
        processWorkerExit(w, completedAbruptly);
    }
}

The crucial part here is calling to getTask() . 这里的关键部分是调用getTask() Its fragment is: 其片段是:

 if (rs >= SHUTDOWN && (rs >= STOP || workQueue.isEmpty())) {
     decrementWorkerCount();
     return null;
 }

The method is not synchronized and relies only on ordering supplied by CAS'ed ctl value. 该方法不同步,仅依靠CAS'ed ctl值提供的排序。 ctl here is the global pool state stored inside AtomicInteger (for non-blocking atomic ThreadPoolExecutor state acquiring). 这里的ctl是存储在AtomicInteger内部的全局池状态(用于非阻塞原子ThreadPoolExecutor状态获取)。

So the following case is possible. 因此,以下情况是可能的。

  1. Worker thread called getTask 名为getTask工作线程
  2. Worker thread acquired run state of the pool. 辅助线程获取了池的运行状态。 It is still RUNNING . 它仍在RUNNING
  3. Another thread initiated an order shutdown and modify ctl accordingly. 另一个线程启动了命令关闭并相应地修改了ctl
  4. Worker thread already took a task from the work queue. 工作线程已经从工作队列中接了一个任务。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM