同步线程池ExecutorService

时间:2018-07-01 18:28:58

标签: java multithreading synchronization threadpool

这是我第一次使用线程池,我不太了解executorservice的工作方式。我将水印放在图像上,然后将它们合并到一张空白图片上。但是,即使我只使用一个线程,它也只会画一半。

这是我的 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);
    }
}

这就是我在 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();

线程不等到一个线程完成吗?

1 个答案:

答案 0 :(得分:0)

ThreadPoolExecutor关机和任务执行/排空工作队列/从工作队列中取出的事情很普通。因此,您不能依赖线程中断机制或其他方法。您所能保证的是:

  

启动有序关闭,其中先前提交的任务位于   执行,但不会接受新任务。调用没有   如果已经关闭,则会产生其他效果。

     

此方法不等待先前提交的任务完成   执行。

要深入研究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);
    }
}

此处的关键部分是调用getTask()。其片段是:

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

该方法不同步,仅依赖于CAS的ctl值提供的顺序。 ctlAtomicInteger内部存储的全局池状态(用于获取非阻塞原子ThreadPoolExecutor状态)。

因此,以下情况是可能的。

  1. 名为getTask的工作线程
  2. 工作线程获取了池的运行状态。仍然是RUNNING
  3. 另一个线程启动了订单关闭并相应地修改了ctl
  4. 工作线程已经从工作队列中接过任务。