仅锁定单个入口点

时间:2016-03-01 17:31:00

标签: java multithreading concurrency executorservice

我正在利用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方法被调用时,我认为我不需要锁定和解锁。

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

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

3 个答案:

答案 0 :(得分:0)

由于Executor实际上是一个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 :(得分:0)

@Obicere,你是对的,你不需要锁定会有性能开销的postRequest。 在postRequest

中使用类似的内容
  public Future<Object> postRequest(final Callable<Object> request) {
        try {
            while(serviceLock.isLocked()) { // i.e acquired by setSize method
                Thread.currentThread().sleep(/*some very small time */); 
            }
            return service.submit(request);
        } finally {

        }
    }

另外,请考虑使用ThreadPoolExecutor而不是FixedPoolThread,因为在您的情况下,它从来不是固定的池线程:)

答案 2 :(得分:0)

您可以显式创建线程池执行程序,然后使用setMaximumPoolSize():

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


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