首页 > 解决方案 > 自定义线程池 - 在不调用 start() 的情况下调用可运行

问题描述

我试图了解自定义线程池实现,如https://www.roytuts.com/custom-thread-pool-in-java/中所述。轮询出任务队列后

while ((r = taskQueue.poll()) != null) {
          r.run();
       }

代码直接调用run方法而不start()先调用。所以,我有点困惑如何启动runnable而不在runnable上创建线程然后调用start方法?任何人都可以在我缺乏理解的地方消除我的困惑。谢谢

class CustomThreadPool {
    // holds tasks
    private BlockingQueue<Runnable> runnableQueue;
    // holds the pool of worker threads
    //private List<WorkerThread> threads;
    // check if shutdown is initiated
    private AtomicBoolean isThreadPoolShutDownInitiated;
    public CustomThreadPool(final int noOfThreads) {
        this.runnableQueue = new LinkedBlockingQueue<>();
        //this.threads = new ArrayList<>(noOfThreads);
        this.isThreadPoolShutDownInitiated = new AtomicBoolean(false);
        // create worker threads
        for (int i = 1; i <= noOfThreads; i++) {
            WorkerThread thread = new WorkerThread(runnableQueue, this);
            thread.setName("Worker Thread - " + i);
            thread.start();
           // threads.add(thread);
        }
    }
    public void execute(Runnable r) throws InterruptedException {
        if (!isThreadPoolShutDownInitiated.get()) {
            runnableQueue.put(r);
        } else {
            throw new InterruptedException("Thread Pool shutdown is initiated, unable to execute task");
        }
    }
    public void shutdown() {
        isThreadPoolShutDownInitiated = new AtomicBoolean(true);
    }


    private class WorkerThread extends Thread {
        // holds tasks
        private BlockingQueue<Runnable> taskQueue;
        // check if shutdown is initiated
        private CustomThreadPool threadPool;
        public WorkerThread(BlockingQueue<Runnable> taskQueue, CustomThreadPool threadPool) {
            this.taskQueue = taskQueue;
            this.threadPool = threadPool;
        }
        @Override
        public void run() {
            try {
                // continue until all tasks finished processing
                while (!threadPool.isThreadPoolShutDownInitiated.get() || !taskQueue.isEmpty()) {
                    Runnable r;
                    // Poll a runnable from the queue and execute it
                    while ((r = taskQueue.poll()) != null) {
                        r.run();
                    }
                    Thread.sleep(1);
                }
            } catch (RuntimeException | InterruptedException e) {
                throw new CustomThreadPoolException(e);
            }
        }
    }
    private class CustomThreadPoolException extends RuntimeException {
        private static final long serialVersionUID = 1L;
        public CustomThreadPoolException(Throwable t) {
            super(t);
        }
    }
}

public class ThreadPoolTest {
    public static void main(String[] args) throws InterruptedException {
        Runnable r = () -> {
            try {
                Thread.sleep(1000);
                System.out.println(Thread.currentThread().getName() + " is executing task.");
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
        };
        CustomThreadPool threadPool = new CustomThreadPool(2);
        threadPool.execute(r);
        threadPool.execute(r);
        threadPool.shutdown();
        // threadPool.execute(r);
    }
}

标签: javamultithreading

解决方案


您的线程池类调用thread.start()哪个调用runnable.run()调用thread.run(). 最后一种方法是为使用 runnable 初始化的线程设计的,可以直接调用,也可以通过start().

根据Oracle 文档start() 导致该线程开始执行;Java 虚拟机调用该线程的 run 方法。

编辑

调用runnable.run()方法只是在当前线程(调用该方法的线程)上同步执行 runnable。在您的情况下,它是单独的(在 CustomThreadPool 中创建)。可以run()直接调用 in main(),会在主线程上同步执行runnable。通常,该示例不会破坏使用可运行对象的任何概念,因为它在单独的线程上执行它们。

长话短说:异步行为是通过在不同线程上执行可运行文件来实现的。在单个线程的范围内,调用多个runnablesrun()会一个一个地同步执行。


推荐阅读