简体   繁体   中英

Multi threading lock methods

Ex 1)

public void addName(String name) {
    synchronized(this) {
        lastName = name;
        nameCount++;
    }
    nameList.add(name);
}

Ex 2)

public class MsLunch {
    private long c1 = 0;
    private long c2 = 0;
    private Object lock1 = new Object();
    private Object lock2 = new Object();

    public void inc1() {
        synchronized(lock1) {
            c1++;
        }
    }

    public void inc2() {
        synchronized(lock2) {
            c2++;
        }
    }
}

I got these two java code from java website but I don't clearly see the difference between these two. Could you guys give more explanation which case I should use this interchangeably? Thanks in advance

There are two differences:

  • The first example locks on this instead of a private reference. I view this as a bad idea in general - it means other code could also lock on the same monitor, which makes it harder to reason about your code. Unless you want other code to be able to acquire a lock on the same monitor (in which case I'd usually expose a monitor explicitly for that purpose), why put yourself at the mercy of other code? The lock should be an implementation detail in most cases, but making it a public reference (which this is effectively) makes that implementation detail visible to the world.
  • The second example shows two methods within the same class locking on different references. That means two threads could call inc1 and inc2 concurrently. If there were multiple methods in the first example, all locking on this , then only one thread could enter any of those methods at a time.

I typically use a single lock for everything within a single class unless I have good reason to believe that there are going to be lots of independent operations working on only part of the state of the class - in which case that suggests the class may be too big to start with.

I also make my "lock variables" final, as you pretty much never want to be able to change them during the lifetime of an object.

So if I really wanted to use locks, I'd probably end up writing the second example as:

public class MsLunch {
    private long c1 = 0;
    private long c2 = 0;
    private final Object lock = new Object();

    public void inc1() {
        synchronized(lock) {
            c1++;
        }
    }

    public void inc2() {
        synchronized(lock) {
            c2++;
        }
    }
}

However, I'd also consider:

  • Not making the instance methods thread-safe to start with. I find it's relatively rare that a single instance of a class will be used from multiple threads concurrently. (Static methods should usually be thread-safe though.)
  • Using AtomicLong instead of locking. Often using a higher-level concept instead of threading primitives can make your code simpler to understand and more efficient.

In the first example you are synchronizing on the this object (the actual class object. This is sufficient in most cases, consider it a coarse grain lock.

In the second example you are locking on created objects with the sole purpose of locking. This approach allows you to have finer grain of control on the locking (in this situation there are two locks going at the same time, the class object doesn't get locked up)

Additionally if you synchronize a method it is pretty much the same as synchronizing on the this object. Basically they are interchangeable, but you might prefer one based on your situation with lock control.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM