tl;dr, don’t use locks unless you really know what you are doing, and even then don’t use them. There is almost always a better way.
99.9% of the time you don’t need locks. You only need locks if:
-
You have a provable situation where the triggers for a Rule are likely, in an non-error case, to occur fast enough that you end up with multiple instances of the rule executing at the same time. This already limits the number of cases down to those with a Thread::sleep. Alternatively you have two Rules which operate on the same Items which are likely to run at the same time. This is more likely but easily handle able without resorting to locks.
-
If you have 1 then if having multiple instances of the rule running at the same time is likely to cause negative in-determinant behavior. In the example I have above, if the rapid turning on and off of the device isn’t a problem and I’m controlling something like the HVAC, who cares if multiple instances of the rule execute at the same time? In the end I am left with the same result. If the Rule does just one thing every time, again who cares if it happens to do it twice? It is only a problem if there is some limitation (e.g. sending two ONs to a device really close together causes a problem) or the order of operations matter (e.g. you don’t want two instances running at the same time because they interfere with each other which is what I tried to show in the example).
-
If you have 1 and 2, then use a lock only if you can find no other way to accomplish what you are trying to do. Perhaps rework your rules or Items so having them run at the same time doesn’t matter. Perhaps implement a proxy or a Timer to filter or ignore the second event while the first one is still running.
Locks are a dangerous thing to use. They can cause deadlock situations (e.g. there are two resources needed by two rules, one grabs one lock, the other rule grabs the second lock and now both are stuck waiting for the lock they don’t have).
Locks make it really hard for the Thread pool, Thread scheduler, and even the down to the CPU scheduler to optimize the execution of your code because it is much more difficult to predict what needs to be executed next when you have Threads locked.
Implementing locking and unlocking in a safe and correct manner is a hard task for the experienced programmer to get right. Most programmers I’ve worked with over the years, including myself, treat locks like “goto”. It can sometimes get you out of a pinch but you had better have a REALLY good reason to use it because the negatives far outweigh the positives on almost all cases. Most of the time I’ve seen locks used (or goto), including in my own code, it is out of laziness rather than because of need.
And in the vast majority of cases, particularly in the domain of openHAB Rules, they are simply unnecessary. They add a bunch of lines of code and global vars which effectively do nothing except give the rule’s coder a nice fuzzy feeling that they have somehow made their Rules be more deterministic. But the feeling is a false one because unless your home automation system is generating events that cause a Rule to be triggered so fast that you have multiple instances running at the same time routinely and not as an error your Rules are already running perfectly deterministicly.
Implementing locks like this would fall into the same categorization as premature optimization. Don’t spend time complicating your code solving something that isn’t actually a problem.
If you want to spend your time on something, spend it on making it so even if your rules are executing multiple instances at the same time it doesn’t matter. This will result in simpler, safer, and more error resistant code and it will allow your rules to run as fast and efficiently as possible.