仅锁定在单个入口点
Locking only on a single entry point
我正在使用 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
?
由于 Executor 实际上是一个 ThreadPoolExecutor,您可以应用强制转换并使用其 setMaximumPoolSize 方法。
您可以在 setSize 方法中添加类型检查,以防将来更新 JVM 规范。
if (e instanceof ThreadPoolExecutor) {
((ThreadPoolExecutor) e).setMaximumPoolSize(size);
}
@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,因为在您的情况下,它从来都不是固定池线程:)
您可以显式创建一个线程池执行器,然后使用 setMaximumPoolSize():
private final ThreadPoolExecutor service = new ThreadPoolExecutor(4,4,0, TimeUnit.MINUTE, new LinkedBlockingQueue());
public void setSize(final int size) {
service.setMaximumPoolSize(size);
}
我正在使用 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
?
由于 Executor 实际上是一个 ThreadPoolExecutor,您可以应用强制转换并使用其 setMaximumPoolSize 方法。
您可以在 setSize 方法中添加类型检查,以防将来更新 JVM 规范。
if (e instanceof ThreadPoolExecutor) {
((ThreadPoolExecutor) e).setMaximumPoolSize(size);
}
@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,因为在您的情况下,它从来都不是固定池线程:)
您可以显式创建一个线程池执行器,然后使用 setMaximumPoolSize():
private final ThreadPoolExecutor service = new ThreadPoolExecutor(4,4,0, TimeUnit.MINUTE, new LinkedBlockingQueue());
public void setSize(final int size) {
service.setMaximumPoolSize(size);
}