1

我有多个可运行的类,我想通过一个集中的类使用执行器服务运行它们(称之为 Launcher 类,其中包含所有可运行的列表)。

我写了一个Launcher类,它使用所有的 bean 来实例化applicationContext.getBean(). 每个可运行类还pool size为它定义一个(为此可运行类产生的线程数)。

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

在执行此操作的过程中,我将所有可运行对象添加到一个List<Daemon>(其中 Daemon 是由其他守护进程扩展的抽象可运行类)。

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.
    }

}

如您所见,我在执行时多次添加每个可运行类的相同实例(取决于 poolSize)。

executor作为一个ScheduledThreadPoolExecutor.

在调用run 方法的那一刻,R我两次都找到了相同的可运行类实例,因为它们只被使用一次appContext.getBean()(通过打印 hasCode 和 toString 进行检查)。

但是这些可运行类的多个实例同时运行。

这种情况可能有什么问题?这些为同一个可运行对象运行的多个线程会导致问题还是会正常运行?

作为替代方案,根据 poolSize,我甚至可以在此循环之前获取 Runnable 类的多个实例,并且根据列表中存在的所有“Runnable”条目仅循环一次。

  1. 所有 bean 本质上都是原型(尽管它不会出现,因为我只调用了一次 appContext.getBean)。
  2. 一个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;
        }
    }
    
4

2 回答 2

2

如果您有一个任务被多次执行,那是因为您多次添加了它。

我建议您在添加任务时登录以确认这一点。

但是同一个线程执行两个线程的任务怎么会发生呢?

一个线程不能同时执行两个任务,但它可以一个接一个地执行一个任务,重复使用同一个线程。

是不是“我有两个'Runnable'类的实例”,如果那个bean是单例的,情况就不会如此?

在这种情况下,我不相信添加两个相同的任务或两次添加相同的任务会产生很大的不同。

于 2012-10-31T15:52:41.637 回答
0

由于 Daemon 类不是线程安全的,因此从多个线程运行相同的实例(Runnable 类型)是危险的。从多个线程运行同一实例的方法总是很危险的,除非对对象的访问受到监视器(同步关键字)的保护。

然后,池中的所有线程只执行单个 Runnable 对象。线程池是为我们有许多小型 Runnables 但不想为每个实例花费一个线程的用例而设计的。由于您的任务是轮询数据库,因此每个任务都有一个线程是合乎逻辑的,但是您不需要创建线程池:只需为每个任务启动一个新线程(包括 daemonList 中某些类的多个线程)。

您写道:“但是这些可运行类的多个实例同时运行”。当然,因为你是这样编程的。线程是同时运行事物的工具。线程是否将 Runnable 类型的相同或不同对象作为要执行的任务并不重要。

于 2012-10-31T17:13:05.913 回答