3

I am using an annotation on some classes and by reflection I get some string of that annotation which is unique for every class.

I am thinking of using that string to synchronize a block of code, but I want to block access of the code only if annotation string value is same, if string is not same than another thread can enter a perform its task. I know that I can't use string directly and ints don't have monitor so I can't use hashcode directly. Is this way going to create any issue when I use jMeter to load test this piece of code.

public class LockObject {

   private String lockString;

   public LockObject(String lockString) {
       this.lockString = lockString;
   }

   public int hashCode() {
       returns hashcode for string;
   }

   @Override
   public boolean equals(Object obj) {
   }
}

public class TestClass {

   public void someMethod() {
       String annotationString = "fetchedByAnnotation that i use on some class by reflection";
       //what i want if string is same then second thread won't enter this block
       synchronized (new LockObject(annotationString)) {
           //some task based on that string
       }
   }
}
dreamcrash
  • 47,137
  • 25
  • 94
  • 117

1 Answers1

3

I know that I can't use string directly and ints don't have monitor so I can't use hashcode directly.

Yes, nonetheless, you could (but you should not) take advantage of the method intern(). From source one can read:

The java string intern() method returns the interned string. It returns the canonical representation of string.

It can be used to return string from memory, if it is created by new keyword. It creates exact copy of heap string object in string constant pool.

String annotationString = // ...;
synchronized (annotationString.intern())

Notwithstanding, the problem of locking on strings is that other objects could inadvertently be locking on those same strings for entirely different purposes. In other words, strings have a global semantic scope, that you cannot control, i.e., ensure that those same strings are not being used elsewhere as a locking mechanism. From this SO Thread (among other points) one can read:

Locking on strings is discouraged, the main reason is that (because of string-interning) some other code could lock on the same string instance without you knowing this. Creating a potential for deadlock situations.

Now this is probably a far fetched scenario in most concrete situations. It's more a general rule for libraries.

An alternative solution would be to have a Map of <String, Object> where the key is the string read from the annotation, and the value would be an object which threads can use to synchronize.

The Map would be shared among threads, therefore one would have to ensure mutual exclusion when accessing such a Map. Every time a thread reads a string from an annotation adds that string to the Map if not yet added, otherwise synchronizes on the value associated with that string key.

dreamcrash
  • 47,137
  • 25
  • 94
  • 117
  • 1
    I would have a look at a striped lock. So just an array of lock objects and use the hash of the string to determine the lock index. – pveentjer Jan 18 '21 at 05:16
  • @pveentjer Yep, I agree, it goes directly to the point, with the added benefit of a more sophisticated locking mechanism, albeit slight more complex as well. – dreamcrash Jan 18 '21 at 21:36