[英]java: executors + tasks + locks
假設我有一個ExecutorService(可以是一個線程池,因此涉及並發),它可以在不同的時間執行任務,定期或響應某些其他條件。 要執行的任務如下:
我正試圖想辦法實現這個。 它應該是這樣的:
Runnable task = new Runnable() {
final SomeObj inProgress = new SomeObj();
@Override public void run() {
if (inProgress.acquire())
{
try
{
algorithmX();
}
finally
{
inProgress.release();
}
}
}
}
// re-use this task object whenever scheduling the task with the executor
SomeObj
是ReentrantLock (acquire = tryLock()
和release = unlock()
)或者是AtomicBoolean等等,但我不知道哪個。 我在這里需要一個ReentrantLock嗎? (也許我想要一個非重入鎖,以防algorithmX()
導致這個任務遞歸運行!)或者AtomicBoolean會不夠?
編輯:對於非重入鎖定,這是否合適?
Runnable task = new Runnable() {
boolean inProgress = false;
final private Object lock = new Object();
/** try to acquire lock: set inProgress to true,
* return whether it was previously false
*/
private boolean acquire() {
synchronized(this.lock)
{
boolean result = !this.inProgress;
this.inProgress = true;
return result;
}
}
/** release lock */
private void release() {
synchronized(this.lock)
{
this.inProgress = false;
}
}
@Override public void run() {
if (acquire())
{
// nobody else is running! let's do algorithmX()
try
{
algorithmX();
}
finally
{
release();
}
}
/* otherwise, we are already in the process of
* running algorithmX(), in this thread or in another,
* so don't do anything, just return control to the caller.
*/
}
}
你建議的鎖定實現很弱,因為某人很容易不正確地使用它。
下面是一個更有效的實現,具有與您的實現相同的不正確的使用弱點:
AtomicBoolean inProgress = new AtomicBoolean(false)
/* Returns true if we acquired the lock */
private boolean acquire() {
return inProgress.compareAndSet(false, true);
}
/** Always release lock without determining if we in fact hold it */
private void release() {
inProgress.set(false);
}
你的第一段代碼看起來很不錯,但如果你擔心algorithmX以遞歸方式調用任務,我建議你使用java.util.concurrent.Semaphore作為同步對象,而不是ReentrantLock 。 例如:
Runnable task = new Runnable() {
final Semaphore lock = new Semaphore( 1 );
@Override public void run() {
if (lock.tryAcquire())
{
try
{
algorithmX();
}
finally
{
lock.release();
}
}
}
}
特別注意try acquire的使用。 如果獲取鎖定失敗,則不運行algorithmX 。
ReentrantLock
對我來說似乎很好。 我發現使用AtomicInteger
手動創建鎖定的唯一情況是,如果你有一個非常簡短的algorithmX
AtomicInteger
而不是你的情況。
我認為選擇正確的鎖定impl的秘訣是:*如果此任務已在進行中,則不執行任何操作(並讓先前運行的任務完成)。
在這種情況下,“無所事事”意味着什么? 運行algorithmX完成后,線程應該阻塞並重試執行? 如果是這種情況,則應使用semaphore.acquire而不是tryAcquire,並且AtomicBoolean解決方案將無法按預期工作。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.