2012-07-08 45 views
2

的第一個電話我有一個方法,這方法裏面我有一個塊:調用方法塊只爲方法

public void method() 
{ 
    [block instructions] 
} 

但這種方法在我的節目叫了兩聲。我希望這個塊只能執行一次,並且只能用於該方法的第一次出現。什麼是最好的和優雅的方式來做到這一點?

回答

7
private static final AtomicBoolean hasRunAtom = new AtomicBoolean(); 

public void method() { 
    if (hasRunAtom.getAndSet(true)) return; 
    [block instructions] 
} 
+0

爲什麼關鍵字會揮發? – user1508419 2012-07-08 10:19:43

+0

用於併發。看到更新的答案,如果兩個線程想要同時運行該方法,我的第一個解決方案將不會很好。 – 2012-07-08 10:21:01

2

在大大過度工程的風險我實際上建議。基本上你有一個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(); 
} 
+0

+1大大過度工程:) – oxc 2012-07-08 10:42:09

+0

這有教育價值,如果沒有別的。但是,它具有非線程安全性。過度設計的解決方案應該至少涵蓋所有角度,你不同意嗎? – 2012-07-08 10:44:14

+0

@MarkoTopolnik:你說的對,我忘了提及它(但是OP也沒有提到線程安全的要求)。不過,我會將它列入我的答案中,謝謝! – 2012-07-08 10:56:50

0

首先,如果你想簡單快捷的方式,使用簡單的布爾標誌(只是不要忘記併發問題並使用@Marko Topolnik解決方案)。

但是,如果我們已經開了一個理論討論並討論設計模式,而不是像@Tomasz Nurkiewicz提到的使用狀態模式,我會建議考慮(有人會說它更反對設計模式)以及如何只能實現這個類的一個實例,所以如果請求這個類的實例,構造函數將僅在第一次調用中被調用。

如果你altentivly想要更多的解決方案「條條框框」,你可以使用

+0

恰當地實現一個懶惰初始化單例的代碼是相當複雜的(除非只是拋出'synchronized')。 – 2012-07-08 11:51:31

+0

你是絕對正確的,但是如果你使用java,你可以使用enum-一個經典而易於編寫的單例。 – shem 2012-07-08 11:55:03

+0

'enum'只適用於一個熱切初始化的單例,這不適合OP的場景。 – 2012-07-08 12:25:32

0

你或許應該重新設計你的方法。如果一個方法在第二次運行時做了不同的事情,那麼試圖理解程序的人會感到困惑。

第二次在程序中的不同位置調用它嗎?如果是這種情況,最簡單的方法是將重複的位提取到另一個方法中。

method() { 
    // Do stuff that's run only the first time 
    method2() 
} 

method2() { 
    // Do stuff that's run both times 
} 

如果它是從同一個地方叫,你應該問自己,爲什麼你的代碼是期待着什麼不同發生第二次。

1

一個簡單的解決辦法是使用一個靜態布爾標誌:

static boolean flag = true; 

public void method() 
{ 
    if (flag) 
    { 

     [block instructions] 
     flag = false; 

    } 
} 
+0

它爲我工作 – 2018-01-18 11:45:23

0

馬爾科的答案很簡單概念,而是方法每次調用現在需要在的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()的調用都會立即返回,而不會執行任何實際的代碼。從性能的角度來看,你正在用一個簡單的分支和返回操作來取代一個沉重的原子操作。