Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
268 views
in Technique[技术] by (71.8m points)

java - How can I make sure a method is only called once by multiple threads?

I have the following structure:

public void someMethod(){  
   //DO SOME STUFF
   try{  
    doSomeProcessing();  
   }  
   catch (Exception e){  
        loadSomeHeavyData();  
        doSomeProcessing();      
   }    
}  

The method someMethod may be called concurrently by many threads. The doSomeProcessing may throw an exception (it is using some data in the backend that could become obsolete).
If an exception is thrown then loadSomeHeavyData(); does some timeconsuming task that let's say "updates" all the current data and I am able to call doSomeProcessing();.
Problem: How can I make sure that loadSomeHeavyData(); is called only once? If I put some atomic flag in the entry of loadSomeHeavyData(); then I can not be sure when this should be cleared.
How can I solve this? Just a note: I can not modify doSomeProcessing(); as it is an external API and I am using decorator pattern to use it.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Your loadSomeHeavyData method could use a blocking mechanism to make all threads wait until it has finished its update, but only let one of them actually do the update:

private final AtomicBoolean updateStarted = new AtomicBoolean();
private final CountDownLatch updateFinished = new CountDownLatch(1);

public void loadSomeHeavyData() {
    if (updateStarted.compareAndSet(false, true)) {
        //do the loading
        updateFinished.countDown();
    } else {
        //update already running, wait
        updateFinished.await();
    }
}

Note my assumptions:

  • you want all the threads to wait until the loading completes so they can call doSomeProcessing a second time with updated data
  • you only call loadSomeHeavyData once, ever - if not you will need to reset the flag and the CountdownLatch (which would then probably not be the most appropriate mechanism).

EDIT

Your latest comment indicates that you actually want to call loadSomeHeavyData more than once, just not more than once at a time.

private final Semaphore updatePermit = new Semaphore(1);

public void loadSomeHeavyData() {
    if (updatePermit.tryAcquire()) {
        //do the loading and release updatePermit when done
        updatePermit.release();
    } else {
        //update already running, wait
        updatePermit.acquire();
        //release the permit immediately
        updatePermit.release();
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...