2016-03-01 13 views
0

我正在使用ExcutorService来提交并行运行的任务。任务的顺序无关紧要。但是,服务可能会发生变化,特别是在请求的池的大小需要更改时。仅在单个入口点锁定

public class Service { 

    private volatile ExecutorService service = Executors.newFixedThreadPool(4); 

    private final ReentrantLock serviceLock = new ReentrantLock(); 

    public Future<Object> postRequest(final Callable<Object> request) { 
     try { 
      serviceLock.lock(); // ? 
      return service.submit(request); 
     } finally { 
      serviceLock.unlock(); // ? 
     } 
    } 

    public void setSize(final int size) { 
     try { 
      if (size <= 0) { 
       throw new IllegalArgumentException("service pool size must positive"); 
      } 
      serviceLock.lock(); 

      service = Executors.newFixedThreadPool(size); 
     } finally { 
      serviceLock.unlock(); 
     } 
    } 
} 

很显然,我不认为我需要在postRequest方法的锁定和解锁,当它被调用的唯一方法。

我只需要在访问setSize期间锁定postRequest。否则,锁定和解锁所需的额外时间毫无意义。我认为这是必要的,因为与提交的数百个请求相比,大小很少会改变(可能是一次或两次)。

有没有办法在不需要时(setSize未被访问时)在postRequest上避免锁定?

回答

0

由于执行程序实际上是一个ThreadPoolExecutor,因此您可以应用强制转换并使用其setMaximumPoolSize方法。

如果将来更新JVM规范,您可以在setSize方法中添加一个类型检查。

if (e instanceof ThreadPoolExecutor) { 
     ((ThreadPoolExecutor) e).setMaximumPoolSize(size); 
    } 

https://docs.oracle.com/javase/7/docs/api/java/util/concurrent/ThreadPoolExecutor.html#setMaximumPoolSize(int)

+1

如果OP想要一个'ThreadPoolExecutor'的功能,那么OP应该创建一个类型的变量,并明确创建该类型的对象。使用类型转换或其他方式来颠覆库函数的意图是一种代码异味。当有其他更简单的方法来解决问题时,它的气味更强烈。 –

+0

@james large:这是我的第一个答案。我稍后编辑了尽可能最小的修改代码。可能不是我最好的想法... – Xvolks

0

@Obicere,你是对的,你不需要锁定postRequest这将有性能开销。 使用像这里面postRequest

​​

另外,请考虑使用ThreadPoolExecutor代替FixedPoolThread因为在你的情况,这是从来没有一个固定的池线程:)

0

可以明确创建一个线程池执行人及然后使用setMaximumPoolSize():

private final ThreadPoolExecutor service = new ThreadPoolExecutor(4,4,0, TimeUnit.MINUTE, new LinkedBlockingQueue()); 


public void setSize(final int size) { 
service.setMaximumPoolSize(size); 
}