的第一個電話我有一個方法,這方法裏面我有一個塊:調用方法塊只爲方法
public void method()
{
[block instructions]
}
但這種方法在我的節目叫了兩聲。我希望這個塊只能執行一次,並且只能用於該方法的第一次出現。什麼是最好的和優雅的方式來做到這一點?
的第一個電話我有一個方法,這方法裏面我有一個塊:調用方法塊只爲方法
public void method()
{
[block instructions]
}
但這種方法在我的節目叫了兩聲。我希望這個塊只能執行一次,並且只能用於該方法的第一次出現。什麼是最好的和優雅的方式來做到這一點?
private static final AtomicBoolean hasRunAtom = new AtomicBoolean();
public void method() {
if (hasRunAtom.getAndSet(true)) return;
[block instructions]
}
在大大過度工程的風險我實際上建議state-pattern。基本上你有一個State
抽象:
interface State extends Runnable {}
有兩種實現方式:
class FirstState extends State {
public void run() {
//[block of code]
state = new SecondState();
}
}
class SecondState extends State {
public void run() {
//[block instructions]
}
}
的FirstState
開關電流state
:
private State state = new FirstState();
你method()
現在已經沒有條件邏輯:
public void method()
{
state.run();
}
然而,在案件99%boolean
標誌就足夠了...
UPDATE:上述解決方案不是線程安全的。如果你需要它,簡單AtomicReference<State> state
不會會足夠(見下文馬爾科Topolnik評論),或者你需要同步整個method()
:
public synchronized void method()
{
state.run();
}
+1大大過度工程:) – oxc 2012-07-08 10:42:09
這有教育價值,如果沒有別的。但是,它具有非線程安全性。過度設計的解決方案應該至少涵蓋所有角度,你不同意嗎? – 2012-07-08 10:44:14
@MarkoTopolnik:你說的對,我忘了提及它(但是OP也沒有提到線程安全的要求)。不過,我會將它列入我的答案中,謝謝! – 2012-07-08 10:56:50
首先,如果你想簡單快捷的方式,使用簡單的布爾標誌(只是不要忘記併發問題並使用@Marko Topolnik解決方案)。
但是,如果我們已經開了一個理論討論並討論設計模式,而不是像@Tomasz Nurkiewicz提到的使用狀態模式,我會建議考慮singleton(有人會說它更反對設計模式)以及如何只能實現這個類的一個實例,所以如果請求這個類的實例,構造函數將僅在第一次調用中被調用。
如果你altentivly想要更多的解決方案「條條框框」,你可以使用aop
恰當地實現一個懶惰初始化單例的代碼是相當複雜的(除非只是拋出'synchronized')。 – 2012-07-08 11:51:31
你是絕對正確的,但是如果你使用java,你可以使用enum-一個經典而易於編寫的單例。 – shem 2012-07-08 11:55:03
'enum'只適用於一個熱切初始化的單例,這不適合OP的場景。 – 2012-07-08 12:25:32
你或許應該重新設計你的方法。如果一個方法在第二次運行時做了不同的事情,那麼試圖理解程序的人會感到困惑。
第二次在程序中的不同位置調用它嗎?如果是這種情況,最簡單的方法是將重複的位提取到另一個方法中。
method() {
// Do stuff that's run only the first time
method2()
}
method2() {
// Do stuff that's run both times
}
如果它是從同一個地方叫,你應該問自己,爲什麼你的代碼是期待着什麼不同發生第二次。
一個簡單的解決辦法是使用一個靜態布爾標誌:
static boolean flag = true;
public void method()
{
if (flag)
{
[block instructions]
flag = false;
}
}
它爲我工作 – 2018-01-18 11:45:23
馬爾科的答案很簡單概念,而是方法每次調用現在需要在的AtomicBoolean執行一個原子操作。如果方法()被非常普遍地調用,這將會導致顯着的性能損失。
這是另一個基於單例模式的線程安全解決方案。我預計這會顯着降低性能開銷。
public class MyClass {
public void method() {
BlockRunner.runIfFirst();
}
private static class BlockRunner {
static {
[block insturctions]
}
public static void runIfFirst() {}
}
}
該解決方案基於Singleton lazy-init概念described here。
如果我的理解是正確的,當通過調用runIfFirst()第一次調用BlockRunner時,會調用靜態代碼塊。未來所有對runIfFirst()的調用都會立即返回,而不會執行任何實際的代碼。從性能的角度來看,你正在用一個簡單的分支和返回操作來取代一個沉重的原子操作。
爲什麼關鍵字會揮發? – user1508419 2012-07-08 10:19:43
用於併發。看到更新的答案,如果兩個線程想要同時運行該方法,我的第一個解決方案將不會很好。 – 2012-07-08 10:21:01