Suppose I have a piece of code in Java that I want to be executed synchronously, however when the thread that owns the lock releases that lock, I do not want waiting threads to execute the synchronized code any more. I just want them to wait until the synchronized code has finished running.
So, when thread 1 enters the synchronized code (method, code block) it must get a lock on that code. Any subsequent threads must then wait for the first thread to finish running the code. So far, regular code synchronization.
However in my case, when the first thread is finished, and releases the lock, I want the waiting threads to skip that synchronized piece of code (the code updates a resource that is used by all threads).
How would I go about creating this in Java using the synchronization features? Currently I am not using the sync features, instead I am using a concurrent collection holding the lock (context), like herebelow. However, the process of locking still needs to be synchronized somehow, because two threads are able to get a lock on the context.
Cheers!
Kjeld
/*
* A concurrently accessible set of contexts.
*/
private static final Set<String> LOCKED_CONTEXTS;
static {
LOCKED_CONTEXTS = ConcurrentHashMap.newKeySet(); // meanwhile, I replaced this with Collections.synchronizedSet(new HashSet<>())
}
...
if (!LOCKED_CONTEXTS.contains(context)) {
LOCKED_CONTEXTS.add(context);
log.debug("Locked context: {}", context);
try {
doTask();
} finally {
LOCKED_CONTEXTS.remove(context);
log.debug("Released context: {}", context);
}
} else {
log.debug("Waiting for context to be released: {}", context);
while (LOCKED_CONTEXTS.contains(context)) {
}
log.debug("The waiting is over, context is released: {}", context);
}
I think you want to combine a lock with a semaphore.
tryLock on the lock
if you got it, do work. At the end of the work, mark the semaphore as complete
if you did not get it, wait for the semaphore to complete
Maybe I don't fully understand your use-case, but from what I get you want a piece of code to only run once for all triggers during its execution, but again if any trigger happens outside of the previous execution window.
Does this cover it?
class Work {
private volatile boolean done;
void queueWorkOnce() {
done = false;
actualWork();
}
private synchronized void actualWork() {
if (!done) {
//TODO: do work
done = true;
}
}
}
Related
I have a method which is invoked by multiple threads.
public void notifyCompleted(PlayerDTO winner, PlayerDTO loser) {
PlayerRankedData winnerData = rankedDataMap.get(winner.getId());
PlayerRankedData loserData = rankedDataMap.get(loser.getId());
int pointsToAdd = getPointsToAdd(winnerData, loserData);
int pointsToDeduct = getPointsToDeduct(loserData, winnerData);
winnerData.addMatchPoints(pointsToAdd);
loserData.deductMatchPointsUptoMinimum(pointsToDeduct, minimumMatchPoints);
winnerData.addRewardTokens(tokenPerVictory);
}
And I have another method which is accessed by a scheduler, and runs only once in a month i.e. It resets the monthly ranked data for players.
private void resetLadder() {
for (PlayerRankedData playerRankedData : rankedDataMap.values()) {
int monthlyTokens = playerRankedData.getRewardTokens() * calculateTierMultiplier(playerRankedData);
playerRankedData.setUnlockedTokens(monthlyTokens);
playerRankedData.resetMonthlyDataData(); //This updates reward tokens, matchPoints and other variables which are modified inside notifyCompleted.
updateOnDatabase(playerRankedData);
}
}
What I want is that when resetLadder is running, notifyCompleted waits until resetLadder finishes its execution.
I can make it work by using a lock object and locking the body of notifyCompleted and resetLadder but I don't want to do that because then only 1 thread will be able to access notifyCompleted at a time which I don't want. Its completely fine for multiple threads to access notifyCompleted.
I think busy waiting with an AtomicBoolean can kind of make it work but issue is that if notifyCompleted is running and resetLadder starts running then it will lead to inconsistent state.
So my question is, is there a way to make notifyCompleted to run but only be blocked when resetLadder is running and resetLadder to not start when notifyCompleted is not running.
I currently have the following problem:
I have made a 'Cache Updater Thread', which checks for updates and then sleeps for some amount of time. I have also build a Button, which enables the user to check for updates manually. The Thread is built like this:
public static Thread cacheUpdater = new Thread(new Runnable() {
int milliSecondSleepTime = 10000;
public void run() {
try {
cacheUpdater.setPriority(Thread.MIN_PRIORITY);
//Infinite loop
while (!terminate) {
syncStatus.set(0);
//Check for updates with some methods, not important here.
syncStatus.set(1);
Thread.sleep(this.milliSecondSleepTime);
}
}
catch (InterruptedException e) {
//First check if it is termination time
if (!terminate) {
syncStatus.set(0);
this.run();
}
}
catch (Exception e) {
System.out.println(e);
}
return;
}
});
If the user clicks the manual-update button, the following code is being runned:
#FXML public void syncOnRequest() {
//Only call interrupt, because then it will start again when terminate is still false
CacheManager.cacheUpdater.interrupt();
System.out.println(CacheManager.cacheUpdater.getState().equals(State.TIMED_WAITING));
while (!CacheManager.cacheUpdater.getState().equals(State.TIMED_WAITING)) {
//LOOP FOREVER
}
//Some code that needs to be executed after the cache is updated
}
I would like to continue executing code in the syncOnRequest() method, when the cache updater is ready with its manual update. I had the idea to check if it is sleeping, but this is not working, because the System.out.println() immediately returns true. I have measured the time it takes to do the update, and its between 200 and 400 ms.
What am I doing wrong here? And why is it always returning true?
Additional question: sometimes a click on the button just kills the Thread, because it just woke up. The InterruptedException is not thrown.
How can I make sure the Thread will also restart in that case?
Note that Thread#interrupt() is the only polite way to ask your thread to interrupt itself (unless you explicitly implement another). Using it to restart the check is therefore a bad practice. So is checking the thread state for synchronization purposes and exposing the thread that keeps your cache up-to-date to external clients.
You manager should have a updateCache() method you will call directly from UI code and auto-update thread will call the same method periodically*. In that method, make sure that access to your cached data is either correctly synchronized or it happens atomically.
*) Instead of implementing your own periodic thread, consider using
Timer and TimerTask classes as well as making it a daemon thread.
I am developing a module inside my system where based on some event the user has to receive sms.
I have the following situation
synchronized(notificationPhoneNumber)
{
SmsProvider.sendSms(notificationPhoneNumber, smsText);
}
The code of the method sendSms is running asynchronious:
public static void send(final NotificationPhoneNumber npn, final String smsText)
{
Thread smsSender = new Thread(new Runnable()
{
public void run()
{
//sms sending code runs here....
}
});
smsSender.start();
}
So the question is how long is the notificationPhoneNumber object locked in this case? Is it going to be locked by the time the thread finishes its job or not?
As long as
SmsProvider.sendSms(notificationPhoneNumber, smsText);
doesn't return. That means, your sendsms() method will create a thread and return. Just for that amount of time.
Also, if you start your thread in your method. The created thread will just hold the reference but not the lock after sendsms() returns.
The lock and synchronization are external to sendsms(). Whichever thread calls sendsms()
will acquire the lock and the code within sendsms() has no knowledge of it.
synchronized(notificationPhoneNumber){
...
}
Here NotificationPhoneNumber object will be locked untill synchronized block executed and once it is execution is over, Thread will release the lock of that Object.
A synchronized statement acquires a mutual-exclusion lock (ยง17.1) on
behalf of the executing thread, executes a block, then releases the
lock. While the executing thread owns the lock, no other thread may
acquire the lock.
read more on documentation
I have written some code that submits a callable to an executor, storing the future in a map against an id. In the call method I wait for a flag to be set before proceeding. Basically I need to wait for an external operation to return to me and say we are done - here is the data and now you can continue... I dont think what I have is correct:
public class MyClass implements Callable<Boolean> {
---
---
private boolean done = false;
#override
public Boolean call() {
-- wait for flag to be set...
//continue....
}
}
--main code--
//create the above class..
//submit it...
//get the future store in map...
//-- wait for response from external application...
///tie it up with an id
//set the attribute so the callable can continue and complete..
Questions:
The above will not work as I am returned a Future and not the object. I was thinking of maybe creating a new interface which inherits from the callable class - does that make sense?
I need the thread to wait and then die if no response is received. Is it possible to set that on a thread at all?
You can schedule a task which will cancel the waiting task. When the waiting task finishes it can cancel the scheduled task. (which ever finished first will cancel the other)
This assumes you have a task which is interruptible in the first place.
there is a wait(long timeout) function available.. heres some documentation on it
http://docs.oracle.com/javase/1.5.0/docs/api/java/lang/Object.html
with this wait(long timeout) function, the thread will wait until it gets a notify() (or notifyAll()) OR until the timout expires.
any of the following will break the wait();
notify();
notifyAll();
timout gets reached
Use the Future#get(long, TimeUnit).
This will wait for some time for an answer, and throw a TimeoutException if there is no return value in the given period. Then just catch the exception and let the thread finish grafefully.
How to kill the thread?
.....
How to restart them again in multi threading?
Since your post is tagged "Java," I have a good idea of what you are saying. Let's say you start a thread by doing:
Thread foo = new Thread(someRunnable);
foo.start();
Now that destroy and friends are deprecated, you need a way to kill the thread. Luckily for you, there has always been the concept of "interrupts." Simply change your runnable so that, on interrupt, it exits. Then call the thread's interrupt method.
foo.interrupt();
If you wrote your Runnable to handle this correctly, it will stop whatever it is doing and terminate.
Thread.stop() kills a thread, but you definitely don't want to do this (see the API documentation for an explanation why). Thread.interrupt() sends an asynchronous notification to a thread, so that it can shut itself gracefully.
For a comprehensive text on Java multithreading, I recommend B. Goetz, Java Concurrency in Practice, Addison-Wesley Professional.
The preferred way for a Thread to die is for the execution of the run method to go to completion:
Thread t = new Thread(new Runnable() {
public void run() {
// Do something...
// Thread will end gracefully here.
}
}
Once a thread gracefully dies in the example above, the Thread cannot be restarted. (Trying to call Thread.start on a thread that has already been started will cause an IllegalThreadStateException.)
In that case, one can make another instance of the thread and call start on that.
Probably a good place to get more information on threading would be Lesson: Concurrency from The Java Tutorials.
i wrap my worker threads up in their own class and use a terminated property to kill the thread proc loop.
sorry i dont have a java version to hand right now but you should get the idea from this
http://pastie.org/880516
using System.Threading;
namespace LoaderDemo
{
class ParserThread
{
private bool m_Terminated;
private AutoResetEvent m_Signal;
private string m_FilePath;
...
public ParserThread(AutoResetEvent signal, string filePath)
{
m_Signal = signal;
m_FilePath = filePath;
Thread thrd = new Thread(this.ThreadProc);
thrd.Start();
}
public bool Terminated {
set { m_Terminated = value; }
}
private Guid Parse(ref string s)
{
//parse the string s and return a populated Guid object
Guid g = new Guid();
// do stuff...
return g;
}
private void ThreadProc()
{
TextReader tr = null;
string line = null;
int lines = 0;
try
{
tr = new StreamReader(m_FilePath);
while ((line = tr.ReadLine()) != null)
{
if (m_Terminated) break;
Guid g = Parse(ref line);
m_GuidList.Add(g);
lines++;
}
m_Signal.Set(); //signal done
}
finally
{
tr.Close();
}
}
}
}
The best way to kill a thread is to set up a flag for the thread to watch. Program the thread to exit when it sees the flag is set to true. There's no way to restart a killed thread.
If you want to start, stop, restart threads at will, maybe using the Java 5 concurrency package would be a good idea. You can have an Executor that will do a bit of work, and when you need that bit of work to be done again, you can just re-schedule it to be done in the executor.
Regarding your first query on killing thread:
You can find more details about topic in below SE questions:
How to properly stop the Thread in Java?
How can I kill a thread? without using stop();
How to start/stop/restart a thread in Java?
Regarding your second query of re-starting thread, it's not possible in java.
You can find below details in documentation page
public void start()
Causes this thread to begin execution; the Java Virtual Machine calls the run method of this thread.
The result is that two threads are running concurrently: the current thread (which returns from the call to the start method) and the other thread (which executes its run method).
It is never legal to start a thread more than once. In particular, a thread may not be restarted once it has completed execution.
Instead of plain Threads, you can use advanced concurrent API for thread life cycle management. Have a look at this post for ExecutorService details :
How to properly use Java Executor?