繁体   English   中英

有没有更优雅的方法来基于列表启动线程?

[英]Is there a more elegant way to launch a thread based on a list?

我的程序/类正在获取需要在并行线程中运行的类列表(例如C-1()至C-100())。 每个都是自己的类,并且都有自己的可执行文件,因此我不需要编译,只需运行即可。 虽然每个类都带有一个参数,但每个类内部的逻辑可能非常不同。 因此,没有希望多次启动带有参数的类。

类列表是可变的。 可能有一个类别(C-3())或多个类别(C-1(),C-2(),C-4(),C-3()),它们的顺序可能相同也可能不相同。

我在循环和switch语句中使用了bulk方法,但是对其中的100条进行编码似乎不必要地复杂,并且坦率地说看起来很糟糕。 但这是可行的,并且在最坏的情况下会胜任。 但是,这困扰着我。

case ("C-1")
{
   new C-1("parm").start();
}
etc .... x 100

lambda函数可能会让我到达那里,但超出了我的经验。

我不想掏空它。 这似乎既低效又可能是性能杀手。

在理想的情况下,我会动态地从列表中拉出项目并启动它。 但是我不知道如何动态替换对象名称。 我不想通过任何聪明的链接来减慢它的速度。 我的专业知识不足以解决这一问题。

添加一些东西也很不错,如果列表少于10个,它将在同一线程中运行,并且如果列表大于10,则只能大规模并行运行。 但是那也不是我的专长。

解决此问题的最佳方法是使用ThreadPool 这个想法是,您将产生一个已知数量的线程,并使用这些工作线程来处理一系列任务。 线程本身可以重用,从而避免了创建线程的开销。

https://howtodoinjava.com/java/multi-threading/java-thread-pool-executor-example/

package com.howtodoinjava.threads;

import java.util.concurrent.Executors;
import java.util.concurrent.ThreadPoolExecutor;

public class ThreadPoolExample
{
    public static void main(String[] args)
    {
        ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(2);

        for (int i = 1; i <= 5; i++)
        {
            Task task = new Task("Task " + i);
            System.out.println("Created : " + task.getName());

            executor.execute(task);
        }
        executor.shutdown();
    }
}

在理想的情况下,我会动态地从列表中拉出项目并启动它。 但是我不知道如何动态替换对象名称。

用于这种动态操作的Java子系统和技术称为“反射”。 java.lang.Class类在这里起着核心作用,其余大多数关键类来自于包java.lang.reflect 反射允许您为通过名称标识的类获取Class对象,创建该类的实例,并在这些实例上调用方法。

如果您的C- *类都具有定义start()方法( Thread ?)的公共超类或接口,那么您甚至可以执行常规方法调用而不是反射方法。

假设您要动态实例化的所有类都提供了接受相同参数类型并且要将相同参数值传递给的构造函数,则可以使用它来保存编写100向条件或一百个不同适配器类的过程,或者类似的,对于您的情况。 从原理上讲,它将遵循以下原则:

  • 获取或创建所需类的标准类名称,例如className

  • 获取相应的Class

     Class<?> theClass = Class.forName(className); 
  • 获取一个Constructor代表您要使用的构造函数。 在您的示例中,构造函数采用与String兼容类型的单个参数。 如果声明的参数类型实际上是String本身(而不是ObjectSerializable或...),则可以这样做:

     Constructor<?> constructor = theClass.getConstructor(String.class); 
  • 掌握了这一点,您可以实例化该类:

     Object theInstance = constructor.newInstance("parm"); 

如上所述,您从那里开始的路径取决于是否存在一个共同的超类型。 如果有,那么你可以

  • 强制转换实例并在其上正常调用方法:

     ((MySupertype) theInstance).start(); 

否则,您还需要反射地调用该方法。 所关注的方法不带任何参数的事实对此进行了某种程度的简化:

  • 获取Method实例。

     Method startMethod = theClass.getMethod("start"); 
  • 在对象上调用方法

     startMethod.invoke(theInstance); 

您还提到

添加一些东西也很不错,如果列表少于10个,它将在同一线程中运行,并且如果列表大于10,则只能大规模并行运行。

以上都不是与启动新线程来运行代码直接相关的。 如果那是start()方法将自己完成的事情(例如,如果所涉及的类具有java.lang.Thread作为超类),则避免每个对象在其自己的线程上运行的唯一替代方法是使用不同的方法。

另一方面,如果您从在一个线程中运行的所有内容开始并希望进行并行化,那么按照@PaulProgrammer的答案中所述使用线程池是一个不错的方法。 请注意,如果任务是相互独立的(如您的描述所示),那么尝试确保它们同时运行就没有多大意义。 线程数多于您要在其上运行的内核并不能真正帮到您,线程池对于排队任务以并行执行很有用。 当然,检查列表的size()以确定是将任务发送到线程池还是直接运行任务将很简单。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM