当前位置: 首页 > 知识库问答 >
问题:

ExecutorService-如何在Runnable/Callable中设置值并重用

公良泰宁
2023-03-14

我想使用ExecutorService来运行一系列相同的可运行/可调用任务。我到处找了一个教程或示例,但没有涉及到实际设置现有Runnable/Callable对象的值,然后使用submit()将该对象发送回ExecutorService。

基本上,我想做的是:

  • 获取服务器列表。
  • 遍历服务器列表,调用inetAddress.getByName(host)获取每个主机上的数据。
  • 将数据收集到服务器bean中以存储在数据库中。

所以,现在,有10,000个(+)个服务器,这需要花费很长时间。所以,我的想法是使用ExecutorService来管理一个线程池。我似乎不明白的是,如何检测一个线程何时结束,这样我就可以抓取数据了。然后我需要获取列表中的下一个服务器,将其放入任务中,然后将()提交回ExecutorService。

这就是说,到目前为止,我所读到的内容似乎指向以下内容:ExecutorService、submit()、Callable、future。

因此,作为一个psuedo进程:

  • 获取服务器列表。
  • 使用numThreads设置ExecutorService线程数
  • 迭代numThreads并创建numThreads WorkerTask()对象。
  • 将()WorkerTask()提交给ExecutorService进行处理。
  • 检测WorkerTask()完成时,获取可调用的(未来)结果。
  • 获取下一个服务器。
  • 将服务器值设置到WorkerTask()<--如何设置?这是难以捉摸的...
  • submit()将WorkerTask()(带有新值)返回ExecutorService。
  • 再次迭代。
  • ExecutorService.Shutdown()...

因此,这方面的教程或示例将非常棒……尤其是将新值放入WorkerTask()中的示例。此外,我希望对这个提议的解决方案有任何意见?这是坏的还是好的,或者如果有别的办法,我是开放的。

02/09/2014-编辑和添加

public List<ServerBean> lookupHostIps ( List<ServerBean> theServerList ) {
    //ServerBean                      serverDto   = null;
    ServerBean                      ipDto       = null;
    List<ServerBean>                theResults  = new ArrayList<ServerBean>();
    List<HostLookupWorker>          theWorkers  = new ArrayList<HostLookupWorker>( getNumberThreads() );
    List<Future<HostLookupWorker>>  theFutures  = new ArrayList<Future<HostLookupWorker>>( getNumberThreads() );

    ExecutorService executor = Executors.newFixedThreadPool ( getNumberThreads() );

    // WORKERS : Create the workers...prime them with a server
    // bean...
    // 
    for (int j = 0; j < getNumberThreads(); j++) {
    //for (int j = 0; j < theServerList.size(); j++) {
        theWorkers.add ( new HostLookupWorker( theServerList.get(j) ) );
        Future<HostLookupWorker> theFuture = executor.submit ( theWorkers.get ( j ) );
        theFutures.add ( j, theFuture );
    }

    int     lloopItems = getNumberThreads();     /* loops thru all servers   */
    //int     lloopThreads = 0;   /* loops thru threads       */
    int     lidxThread = 0;     /* what thread is ready     */
    //int     lidxFuture = 0;     /* what future is ready     */
    boolean lblnNext = false;   /* is a thread done/ready   */
    int lidxWorkers = 0;        /* tracks the futures       */
    while ( lloopItems < theServerList.size() ) {
        // READY : Is one of the threads ready for more work?
        if ( lblnNext ) {
            // VALUE : Grab the thread by index and set the next
            // server value.
            theWorkers.get ( lidxThread ).setBean ( theServerList.get(lloopItems) );
            getLog().debug ( "Thread [" + lidxThread + "] Assigned Host ["+theServerList.get(lloopItems).getServerName ()+"] " );
            // FUTURE : Package a new Future<HostLookupWorker> 
            // and submit it to the thread pool.
            Future<HostLookupWorker> theFuture = executor.submit ( theWorkers.get ( lidxThread ) );
            theFutures.add ( lidxThread, theFuture );
            lblnNext = false;   /* reset to allow for another thread    */
            lloopItems++;       /* increment the main loop counter       */
        }

        while ( !(lblnNext) ) {
            try { 
                if ( theFutures.get(lidxWorkers).get() != null ) {
                    // GET THE STUFF : Grab the results from the Future...
                    HostLookupWorker    ltheItem = theFutures.get(lidxWorkers).get();
                    if ( ltheItem.getValue () != null ) { 
                        if (!ltheItem.getValue ().contains("Cannot find host")){
                            ipDto = new ServerBean ();
                            ipDto.setServerId   ( ltheItem.getBean ().getServerId()   );
                            ipDto.setServerName ( ltheItem.getBean ().getServerName() );
                            ipDto.setIpAddress  ( ltheItem.getValue ()      );

                            theResults.add(ipDto);
                        }
                        lidxThread = lidxWorkers;   /* this thread is ready for more work   */
                        lblnNext = true;            /* flag the upper condition to assign new work  */
                        getLog().debug ( "Thread [" + lidxThread + "] Host ["+ltheItem.getHost ()+"] has IP ["+ltheItem.getValue()+"]" );
                    }
                }
                else { 
                    getLog().debug ( "Thread [" + lidxThread + "] NULL" );
                }

                lidxWorkers++;  /* next worker/future   */

                if ( lidxWorkers >= getNumberThreads() ) {
                    lidxWorkers = 0;
                } 

            } 
            catch(ExecutionException e){  
                getLog().error ( e );
            }
            catch(InterruptedException e){
                getLog().error ( e );
            }

        }
    }

    executor.shutdown ();

    return theResults;
}

下面是Worker/Thread类:

import java.net.*;
import java.util.concurrent.Callable;

import com.lmig.cdbatch.dto.ServerBean;

public class HostLookupWorker implements Callable {

    private InetAddress node = null;
    private String      value = null;
    private boolean     busy = false;
    private ServerBean  bean    = null;

    public  HostLookupWorker () {
        this.busy = false;
    }

//    public  HostLookupWorker ( String theHost ) {
//        this.busy = false;
//        this.host = theHost;
//    }

    public  HostLookupWorker ( ServerBean theItem ) {
        this.busy = false;
        this.bean = theItem;
        //this.host = theItem.getServerName ().trim ();
    }

    public String lookup ( String host ) {

        if ( host != null ) { 
            // get the bytes of the IP address
            try {
                this.node = InetAddress.getByName ( host );
            } 
            catch ( UnknownHostException ex ) {
                this.value = "Not Found [" + getHost() + "]";
                return "Not Found [" + host + "]";
            }

            if ( isHostname(host) ) {
                getBean().setIpAddress ( node.getHostAddress() );
                return node.getHostAddress();
            } 
            else { // this is an IP address
                //return node.getHostName();
                return host;
            }
        }
        return host;

    } // end lookup

    public boolean isHostname(String host) {

        // Is this an IPv6 address?
        if (host.indexOf(':') != -1)
            return false;

        char[] ca = host.toCharArray();
        // if we see a character that is neither a digit nor a period
        // then host is probably a hostname
        for (int i = 0; i < ca.length; i++) {
            if (!Character.isDigit(ca[i])) {
                if (ca[i] != '.')
                    return true;
            }
        }

        // Everything was either a digit or a period
        // so host looks like an IPv4 address in dotted quad format
        return false;
    } // end isHostName

//    public void run() {
//        value = lookup ( getHost() );
//        
//    }

    public Object call() throws Exception {
        Thread.sleep ( 10000 );
        this.busy = true;
        this.value = lookup ( getHost() );
        this.busy = false;
        return this;
    }

    public String getHost() {
        return getBean().getServerName ().trim ();
    }

    public void setHost(String host) {
        getBean().setServerName ( host.trim () );
    }

    public InetAddress getNode() {
        return node;
    }

    public void setNode(InetAddress node) {
        this.node = node;
    }

    public String getValue() {
        return value;
    }

    public void setValue(String value) {
        this.value = value;
    }

    public boolean isBusy() {
        return busy;
    }

    public void setBusy(boolean busy) {
        this.busy = busy;
    }

    public ServerBean getBean() {
        return bean;
    }

    public void setBean(ServerBean bean) {
        this.bean = bean;
    }

}

因此,总结一下:
-这个过程确实有效,而且工作得很快。
-我需要稍微修正一下代码,因为当较大的while()循环最终完成时,还有getNumberThreads()-1个期货未处理...

所以,我现在纠结的是如何检测线程何时结束……我已经看到了多个例子,一个测试Future()!=null,其他的测试Future()==null。那么哪一个是对的呢?

共有1个答案

禹昊穹
2023-03-14

我认为在这种情况下最好的方法是为每个服务器创建一个任务,因为它们将由拉动中的线程执行,然后使用tge future对象检索任务返回的服务器信息。

 类似资料:
  • 使用,我提交了一批任务,任务有一个时间变量,即之间的共享。我想在提交任务之前设置的值。代码如下: 但它出错了 我该怎么解决?

  • 问题内容: 因此,该资源(http://www.ibm.com/developerworks/java/library/j-jtp05236/index.html)建议在该线程不处理中断本身时将其设置为“ 这样,调用堆栈中更高级别的代码就可以了解中断并在需要时对其进行响应 。” 假设我正在使用ExecutorService在其他线程中运行某些内容。我构造一个Callable并将此Callable传

  • 在Java中设计并发线程时,使用和接口有什么区别,为什么要选择其中一个?

  • 我有一个类实例,上面有一个字段。我在对象上设置了这个实例。我需要在Nashorn中设置字段,以便在Java中调用。我该如何在Nashorn脚本中设置此字段? 脚本是这样调用的: 在脚本中,我需要在全局对象上设置字段: 我已经看到了(建议重复)如何使用Nashorn引擎调用Java对象的问题,但这个问题是关于从Nashorn脚本调用Java方法,而这个问题是关于在Nashorn脚本中设置一个可调用的