Java可调用线程:保持配置

时间:2015-12-10 18:43:38

标签: java multithreading callable

我正在设置一个服务器(Radius)的模拟器(用于测试),它使用线程将查询发送到另一个服务器(LDAP)。 查询需要以每秒x为单位执行。 我正在使用一个可调用的调度线程池执行程序,以便我可以创建callables并将它们提交给线程池执行。 每个线程都应该打开自己的连接并使用它来进行查询。 问题是我希望每次使用连接都被同一个线程重用。

澄清:

如果我允许说20个线程池我想要创建和使用20个连接。 (所以我可以发送10.000个查询,这些查询将由20个线程/连接依次处理)。

现在要连接的(LDAP)服务器信息被发送到callable的构造函数,并且callable设置连接以便执行。此后,我使用未来的可调用系统检索结果。 这个问题是每次我创建一个可调用的连接被打开(当然后来关闭)。

我正在寻找保持连接存活的最佳实践,并为每个线程重用它们。

我已经想到了实现这个目标的一些方法,但它们看起来效率不高:

  • 在我的线程池中使用连接池以在需要时检索空闲连接(创建死锁和其他线程安全问题)
  • 使用带有连接的静态(或左)数组和using the thread number来检索其连接(也不是防污,请参阅链接)

实现此目的的最有效方法是什么?< - 旧问题,请参阅编辑新问题。

修改 我在想,因为我不能安全地得到一个线程号,但是threadId总是唯一的,我可以使用

map<String/threadId, connection>

将整个地图(参考)传递给callable。这样我就可以使用:(伪代码)

Connection con = map.get(this.getThreadId());
If (con == null){
  con = new Connection(...);
  map.put(this.getThreadId(), con)
}

也可以使地图静态,只是静态访问它。这样我就不必将地图传递给Callable。 这至少是安全的,并没有迫使我重构我的代码。

新问题: 与最佳实践更接近的内容;以上解决方案或Zim-Zam的解决方案? 如果以上情况最好,那么选择静态解决方案会更好吗?

1 个答案:

答案 0 :(得分:1)

我会使用在BlockingQueue之间共享的Callables来实现这一点,ScheduledThreadPoolExecutorxBlockingQueue次{/ 1}}次

public class Worker implements Runnable {
    private final BlockingQueue<Query> inbox;
    private final BlockingQueue<Result> outbox;

    public Worker(BlockingQueue<Query> inbox, BlockingQueue<Result> outbox) {
        // create LDAP connection
        this.inbox = inbox;
        this.outbox = outbox;
    }

    public void run() {
        try {
            while(true) {
                // waits for a Query to be available
                Query query = inbox.take();
                // execute query
                outbox.add(new Result(/* result */));
            }
        } catch(InterruptedException e) {
          // log and restart? close LDAP connection and return?
        }
    }
}

public class Master {
   private final int x; // number of queries per second
   private final BlockingQueue<Query> outbox = new ArrayBlockingQueue<>(4 * x);
   private final BlockingQueue<Result> inbox = new ArrayBlockingQueue<>(4 * x);
   private final ScheduledThreadPoolExecutor executor;
   private final List<Future<?>> workers = new ArrayList<>(20);
   private final Future<?> receiver;

   public Master() {
     // initialize executor
     for(int i = 0; i < 20; i++) {
         Worker worker = new Worker(inbox, outbox);
         workers.add(executor.submit(worker));
     }

     receiver = executor.submit(new Runnable() {
         public void run() {
           while(!Thread.interrupted()) {
             try {
               Result result = inbox.take();
               // process result
             } catch(InterruptedException e) {
               return;
             }
           }
         }
     }
   }

   executor.scheduleWithFixedDelay(new Runnable() {
       public void run() {
           // add x queries to the queue
       }
   }, 0, 1, TimeUnit.SECONDS);
}

使用BlockingQueue#addQueries添加新outbox,如果这会引发异常,那么您的队列已满,您需要降低查询创建率和/或创造更多的工人。要在其cancel(true)上突破某个工作人员的无限循环调用Future,这会在InterruptedException内部抛出Worker