4

Given the output shown below:

    Path path1 = Paths.get("/Users/someone/foo");
    Path path2 = Paths.get("/Users/someone/foo");
    System.out.println(path1.toString() == path2.toString()); // outputs false
    System.out.println(path1.toString().equals(path2.toString())); // outputs true

Given the following two threads, is it possible for both threads to be running in the critical section at the same time?

    // Thread 1
    synchronized (path1.toString()) {
        // Critical section
    }

    // Thread 2
    synchronized (path2.toString()) {
        // Critical section
    }
albusshin
  • 3,930
  • 3
  • 29
  • 57
  • 1
    Each object has its own monitor; that is what is acquired by the synchronized block. As such, there will only be mutual exclusion if `path1.toString() == path2.toString()`. – Andy Turner Mar 05 '17 at 21:56
  • 1
    In general, synchronizing on the result of method call is not a good idea: even if you're synchronizing just on `path1.toString()` in both threads, you might get no mutual exclusion at all, if it's always returning a new object (you don't know if this is the case, and it could change arbitrarily). – Andy Turner Mar 05 '17 at 21:58
  • And you certainly cannot count on those references to be the same. Most likely they won't be. Anyway, why would you lock on a `String`? `String` carries around a whole lot of freight and semantics to use merely as a lock object. You only need an `Object`. – Lew Bloch Mar 05 '17 at 22:01

2 Answers2

7

The reference is the value. This is a distinction without a difference. toString() is a reference. It won't be the same as any other toString() value unless both have been interned, or they both originated from identical or the same string literals.

user207421
  • 305,947
  • 44
  • 307
  • 483
  • 1
    I think OP was wondering if two strings that test as equal (using `equals()`) would be enough to ensure thread safety. – Ted Hopp Mar 05 '17 at 22:03
  • @TedHopp I don't see any point in speculating about what he may or may not have meant. I'm answering the question he asked. – user207421 Mar 05 '17 at 22:06
  • Yes Ted, I was wondering if `equals()` or `==` is used when judging two objects are equal in the `synchronized ()` keyword. – albusshin Mar 05 '17 at 22:06
  • 1
    @albusshin Then you should have said so in your question. As soon as you actually write it down you can see that it doesn't make sense. Why would `synchronized` be comparing objects? – user207421 Mar 05 '17 at 22:07
  • @EJP I see your point. Pardon my jargon, but I don't know what is the name of the thing we are comparing when we call `.equals()`? – albusshin Mar 05 '17 at 22:10
  • 1
    @albusshin There is no 'thing'. It's a method. It compares anything it likes, or nothing, and returns a value. – user207421 Mar 05 '17 at 22:21
4

As is documented in the Java Language Specification, section 14.19 (JLS), the synchronized statement locks on objects. If you're thinking of "value" as the string value (as in path1.toString().equals(path2.toString())), then then answer is "no"—your code is almost certainly not thread-safe. In the parlance of the JLS, if the type of an expression is a reference type (as required for the synchronized statement), then the value of that expression is either null or an object. The two blocks in your posted code are not mutually exclusive unless the two toString() calls return the same object reference (path1.toString() == path2.toString()).

Ted Hopp
  • 232,168
  • 48
  • 399
  • 521
  • That is the opposite of what the cited reference tells us. It says, "Otherwise, let the non-null value of the Expression be V. The executing thread locks the monitor associated with V." It locks the monitor associated with the expression, not on the reference as this answer purports. Furthermore, as §17.1 states, the monitor is associated with the object, not the reference. "Each object in Java is associated with a monitor, which a thread can lock or unlock." – Lew Bloch Mar 05 '17 at 22:08
  • @LewBloch Again that's a distinction without a difference. It is a reference-valued expression. – user207421 Mar 05 '17 at 22:09
  • Saying the opposite of the JLS rather does make a difference, particularly when it addresses the exact question the OP asked and gives the opposite answer. Not only that, but you only have to read fora like this one for a matter of minutes before you see how much damage the confusion between object and reference (pointer) causes. It matters in locks, GC, polymorphism, copying and cloning, immutability, argument passing (and whether it's by value) - really everything. So your claim that it's "a distinction without a difference" is as opposite to truth as the answer it tries to defend. – Lew Bloch Mar 05 '17 at 22:28
  • 1
    @LewBloch - Fair point. I've updated my wording slightly to clarify that Java locks on objects, not on references. – Ted Hopp Mar 05 '17 at 23:31