user2269170
user2269170

Reputation: 79

Custom Thread Pool - runnable called without calling start()

I was trying to understand for custom thread pool implementation as explained in https://www.roytuts.com/custom-thread-pool-in-java/. After polling out of task queue as

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

the code is directly calling run method without calling start() first. So, i am bit confused how runnable can be started without creating thread on runnable and then call start method? Can anyone please clear out my confusion where i am lacking the understanding. Thanks

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);
    }
}

Upvotes: 1

Views: 470

Answers (1)

Steyrix
Steyrix

Reputation: 3226

Your thread pool class calls thread.start() which calls runnable.run() by calling thread.run(). The last method is designed for threads initialized with runnable and can be called directly or via start().

According to Oracle docs: start() Causes this thread to begin execution; the Java Virtual Machine calls the run method of this thread.

EDIT

Calling runnable.run() method simply synchronously executes runnable on the current thread (in which the method was called). In your case it is separate ones (which are created in CustomThreadPool). You can call run() directly in main(), which will synchronously execute the runnable on the main thread. Generally, the example is not breaking any concepts of using runnables, since it executes them on separate threads.

To make a long story short: asynchronous behavior is achieved by executing runnables on different threads. In scope of a single thread, calling multiple runnables' run() will execute them synchronously one by one.

Upvotes: 1

Related Questions