Same Runnable class being passed twice to the ExecutorService running two/multiple threads at the same time

孤者浪人 提交于 2021-02-08 06:50:51

问题


I have multiple runnable classes and I want to run them with executor service through a centralized class (call it Launcher class which contains list of all runnables).

I wrote a Launcher class which takes all the beans to instantiate using applicationContext.getBean(). Each runnable class also defines a pool size for it (number of threads to spawn for this runnable).

public class DaemonsLauncher {

    @Autowired
    private ApplicationContext appContext;

    private List<Daemon> daemons = new ArrayList<Daemon>();

    private ScheduledThreadPoolExecutor executor;

    private void initThreadPool() throws Exception {
        //daemonNames coming at run time from somewhere.
        List<String> daemonList = Arrays.asList(daemonNames.split(Constant.COMMA));
        //Pool size will now be summation of all the pool sizes.
        int poolSize = 0;
        for (String dName : daemonList) {
            Daemon daemon = appContext.getBean(dName, Daemon.class);
            poolSize += daemon.getPoolSize();
            daemons.add(daemon);
        }
        executor = new ScheduledThreadPoolExecutor(poolSize);
    }

    public void launchDaemons() throws Exception {
        for (Daemon daemon : daemons) {
            for (int currentThreadCount = 1; currentThreadCount <= daemon.getPoolSize(); currentThreadCount++) {
                executor.scheduleWithFixedDelay(daemon, 0, XYZ, ABC);
            }
        }
    }
}

In the process of doing it, I add all runnables to a List<Daemon> (where Daemon is a abstract runnable class which is extended by other daemons).

public abstract class Daemon implements Runnable {

    protected int poolSize = 1;

    public int getPoolSize() {
        return poolSize;
    }

    @Override
    public void run() {
        //Calls run methods of individual runnables here.
    }

}

As you can see, I add same instance of each runnable class multiple times(depending on poolSize) while executing.

executor being a ScheduledThreadPoolExecutor.

The moment, run method of R is called, I find same instance of runnable class both the times since they were taken only once by appContext.getBean() (checked by printing hasCode and toString).

But these multiple instances of runnable class run at the same time.

What might be the issue with this sort of case? Are these multiple threads running for same runnable will cause issues or it will go fine?

As an alternative, depending on poolSize, I can get multiple instances of the Runnable class even before this loop and loop only once depending on all the 'Runnable' entries present in the List.

  1. All beans are prototype in nature (though it will not come into picture as I have called appContext.getBean only once).
  2. A sample Runnable class.

    public class R extends Daemon {
        @Override
        public void runIndividualDaemon() {
            //Called by run of Daemon class.
            logger.info("Running Daemon." + this.hashCode() + " " + this.toString());
        }
    
        @Override
        protected void init() throws Exception {
            this.poolSize = 5;
        }
    }
    

回答1:


If you have a task being performed multiple times, it is because you added it multiple times.

I suggest you log when you add tasks to confirm this.

But how can it happen that same thread is performing task of two threads?

A thread cannot perform two tasks at once, but it can perform one task after another, re-using the same thread.

Is it that "I have two instances of 'Runnable' class" which would not have been the case if that bean was singleton?

I don't believe add two tasks which are the same or adding the same task twice will make much difference in this case.




回答2:


Since Daemon class is not threadsafe, then it is dangerous to run same instance (of type Runnable) from multiple threads. It is always dangerous to run methods of the same instance from multiple thread, unless the access to the object is protected with a monitor (synchronized keyword).

Then, all threads in your pool execute only single Runnable object. Thread pools are designed for use cases where we have many small Runnables but do not want spend a thread for each instance. Since your task is to poll database, it's logical to have a thread for each task, but then you need not to create a threadpool: just start a new thread for each task (including multiple threads for some classes in daemonList).

You wrote: "But these multiple instances of runnable class run at the same time". Sure, because you programmed it that way. The threads are facility to run things simultaneousely. And it doesn't matter if the threads take same or different objects of type Runnable as the task to execute.



来源:https://stackoverflow.com/questions/13161625/same-runnable-class-being-passed-twice-to-the-executorservice-running-two-multip

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!