簡體   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