亚洲在线久爱草,狠狠天天香蕉网,天天搞日日干久草,伊人亚洲日本欧美

為了賬號安全,請及時綁定郵箱和手機立即綁定
已解決430363個問題,去搜搜看,總會有你想問的

使用多個線程僅調用一次方法

使用多個線程僅調用一次方法

HUWWW 2023-02-16 15:46:00
我有一個同時處理大量請求的 Web 應用程序。在應用程序的一個 API 方法中,我有一個方法 - methodA()。在這個方法中,我調用了另一個方法 - doSomething()。我有一個場景,我希望對 methodA() 的第一次調用將在單獨的線程中運行 doSomething() 方法,但此時,如果已調用對 methodA() 的另一個調用,則不要運行 doSomething( ) 方法(因為它仍在由另一個線程運行)并繼續 methodA() 的其余部分。methodA() { . . doSomething() // In a new thread . .}我考慮過使用原子布爾值作為標志,但我不確定這是否是最好的主意。    private final AtomicBoolean isOn = new AtomicBoolean(false);    methodA() {        .        .        if (isOn.compareAndSet(false, true)) {                     Runnable doSomethingRunnableTask = () -> {                          doSomething(); };                     Thread t1 = new Thread(doSomethingRunnableTask);                     t1.start();                     isOn.set(false);        } 謝謝!
查看完整描述

3 回答

?
UYOU

TA貢獻1878條經驗 獲得超4個贊

您可以使用ReentrantLock。鎖一次只允許一個線程,它的tryLock()方法將根據是否獲得鎖立即返回 true 或 false。

ReentrantLock lock = new ReentrantLock();


methodA() {

    ...

    if (lock.tryLock()) {

        try {

            doSomething();

        } finally {

            lock.unlock();

        }

    }

    ...

}

如果您想doSomething()在另一個線程中執行,并且不想阻塞任何調用線程,您可以使用與您最初想到的類似的東西。


AtomicBoolean flag = new AtomicBoolean();


methodA() {

    ...

    if (flag.compareAndSet(false, true)) {

        // execute in another thread / executor

        new Thread(() -> {

            try {

                doSomething();

            } finally {

                // unlock within the executing thread

                // calling thread can continue immediately

                flag.set(false);

            }

        }).start();

    }

    ...

}


查看完整回答
反對 回復 2023-02-16
?
慕容3067478

TA貢獻1773條經驗 獲得超3個贊

我認為您可以使用 ReentrantLock 及其tryLock方法。從文檔ReentrantLock::tryLock

僅當調用時鎖未被另一個線程持有時才獲取鎖。

如果當前線程已經持有此鎖,則持有計數遞增 1,并且該方法返回 true。

如果鎖被另一個線程持有,則此方法將立即返回值 false。

所以你可以在你的服務中創建這樣的鎖作為一個字段,這樣調用你的線程methodA將共享它然后:

public class MyService {

    private ReentrantLock reentrantLock = new ReentrantLock();


    public void methodA() {

        if(reentrantLock.tryLock()) {

            doSomething();

            reentrantLock.unlock();

        }

    }

}

編輯:這里的鎖將通過調用 Thread 來持有,這個線程將等待提交的任務完成然后解鎖鎖:


public class MyService {

    private ReentrantLock reentrantLock = new ReentrantLock();

    

    private ExecutorService pool = Executors.newCachedThreadPool();

    

    public void methodA() {

        if(reentrantLock.tryLock()) {

            Future<?> submit = pool.submit(() -> doSomething()); // you can submit your invalidateCacheRunnableTask runnable here.

            try {

                submit.get();

            } catch (InterruptedException | ExecutionException e) {

                e.printStackTrace();

            } finally {

                reentrantLock.unlock();

            }

        }

    }

}

還要記住,我在這個例子中使用了 threadPool,所以這個池需要適當地關閉


查看完整回答
反對 回復 2023-02-16
?
不負相思意

TA貢獻1777條經驗 獲得超10個贊

我建議您使用阻塞隊列,而不是使用某種顯式鎖。我看到的優點是,如果/當需要時,您不需要重復生成線程。您只需要生成一個線程一次,該線程將只處理所有doSomething。


設想:


調用methodA時,它會將專用線程的必要信息放入 BlockingQueue 并繼續運行。專用線程將從BlockingQueue 中輪詢信息(在空隊列上阻塞)。當隊列中收到一些信息時,它會運行您的doSomething方法。


BlockingQueue<Info> queue;


methodA() {

    //...

    queue.add(info);

    // non-blocking, keeps going    

}



void dedicatedThread(){

    for(;;) {

        //Blocks until some work is put in the queue

        Info info = queue.poll(); 

        doSomething(info);

    }


}

注意:我假設類型Info包含方法doSomething的必要信息。但是,如果您不需要共享任何信息,我建議您改用信號量。在這種情況下,方法 A 會將票放入信號量中,專用線程將嘗試繪制票,阻塞直到收到一些票。


查看完整回答
反對 回復 2023-02-16
  • 3 回答
  • 0 關注
  • 174 瀏覽
慕課專欄
更多

添加回答

舉報

0/150
提交
取消
微信客服

購課補貼
聯系客服咨詢優惠詳情

幫助反饋 APP下載

慕課網APP
您的移動學習伙伴

公眾號

掃描二維碼
關注慕課網微信公眾號