Is there any compilation mechanism in Java to try to ensure the constant use of a particular class?

Our code base now has a class that uses the synchronized at the method level to ensure data consistency in multi-threaded operations. It looks something like this:

 public class Foo { public synchronized void abc() { ... } public synchronized void def() { ... } //etc. } 

The best part is that anyone who uses the class gets synchronization for free. When you create an instance of Foo , you don’t need to remember access to it inside a synchronized block or something like that.

Unfortunately, it seems that synchronization at the method level will no longer shorten it. Instead, we need to start synchronization on Foo . I do not think that something like java.util.concurrent.AtomicReference will cut back either. I want to make sure that no one touches the Foo instance while the specific (and possibly somewhat lengthy) operation is in progress. So, now we will have such blocks in the code:

 Foo foo = new Foo(); //this got created somewhere //somewhere else entirely synchronized(foo) { //do operation on foo foo.doStuff(); foo.doOtherStuff(); } 

So the main thing I'm worried about is that several developers and I share this code. Foo objects are pretty ubiquitous. Since we no longer get synchronization at the method level, we should ALWAYS remember access to the Foo object in the synchronized block.

So my question is: is there any mechanism (built-in or third-party) in Java so that I can generate warnings or errors at compile time if the Foo instance is accessed outside the synchronized block

Ideally, this would be something that I can either do with the class declaration (example below):

 @EnsureSynchronized public class Foo { //etc. } 

Or something that I could do when I declare Foo instances (the example below):

 @EnsureSynchronized private Foo foo; 

I know if I really wanted to be able to write my own FindBugs or PMD rule for this, but I was hoping something similar already existed.

So, I ask you, SO community, if you were in this situation, how would you try to ensure that Foo objects are only ever accessible and changed inside synchronized blocks?

+7
source share
4 answers

Findbugs finds incompatible synchronization pretty well, as long as you have code that synchronizes all calls to the object and runs findbugs, it should warn you about synchronization failures.

A typical error that matches this error pattern forgets to synchronize one of the methods in the class that is thread safe.

You can select the nodes labeled "Unsynchronized access" to show the locations of the code where the detector believed that the field was available without synchronization.

Note that there are various sources of inaccuracy in this detector; for example, the detector cannot statically detect all situations in which the lock is held. Furthermore, even if the detector is accurate in recognizing blocked or unlocked accesses, this code may be right.

If this is not enough, you can always comment on net.jcip.annotations.NotThreadSafe , which findbugs recognizes.

From Chapter 10. Annotations :

FindBugs also supports the following annotations:

  • ...
  • net.jcip.annotations.NotThreadSafe
+6
source

If you want the check to be at compile time, FindBugs and PMD will not. I would suggest a Java Annotation Processing Tool ( APT ). This will create a custom annotation handler that can add checks to the compilation process to use your annotated classes and cause compiler warnings or errors if your synchronization requirements are not met. In fact, you can even use it to fake code to add synchronization at compile time if it does not already exist.

To use the annotation handler you created, you just need to make sure that it is in the class path when compiling your project. No need for additional automatic analysis.

+1
source

If you call notify() without a synchronized block around it or a synchronized method, you will get IllegalMonitorStateExcept (see the documentation ). However, this is very hacky and should, if at all, be used only for debugging, and not in production settings.

0
source

At runtime, you can use Thread.holdsLock () .

Have you thought about inheriting from Foo , such as SynchronizedFoo , and use this in your code, while others can still use Foo as needed?

0
source

All Articles