简体   繁体   中英

Which is more efficient and why?

Out of the below two synchronization strategy, which one is optimized (as in processing and generated byte code) and also the scenario in which one should use one of them.

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

or

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

}

Also what is advisiable way to handle concurrency:

  1. using java.util.concurrent package
  2. using the above low level methods
  3. using Job or UIJob API (if working in eclipse PDE environment)

Thanks

  • Your updated two pieces of code are semantically identical. However, using a synchronized block as in the second piece allows you more control, as you could synchronize on a different object or, indeed, not synchronize parts of the method that don't need to be.
  • Using java.util.concurrent is very much preferrable to using synchronization primitives wherever possible, since it allows you to work at a higher level of abstraction, and use code that was written by very skilled people and tested intensively.
  • If you're working in eclipse PDE, using its APIs is most likely preferrable, as it ties in with the rest of the platform.

which one is optimized (as in processing and generated byte code)

According to this IBM DeveloperWorks Article Section 1 , a synchronized method generates less bytecode when compared to a synchronized block. The article explains why.

Snippet from the article:

When the JVM executes a synchronized method, the executing thread identifies that the method's method_info structure has the ACC_SYNCHRONIZED flag set, then it automatically acquires the object's lock, calls the method, and releases the lock. If an exception occurs, the thread automatically releases the lock.

Synchronizing a method block, on the other hand, bypasses the JVM's built-in support for acquiring an object's lock and exception handling and requires that the functionality be explicitly written in byte code. If you read the byte code for a method with a synchronized block, you will see more than a dozen additional operations to manage this functionality. Listing 1 shows calls to generate both a synchronized method and a synchronized block:

Edited to address first comment

To give other SOers credit, here is a good discussion about why one would use a sync. block. I am sure you can find more interesting discussions if you search around :)

Is there an advantage to use a Synchronized Method instead of a Synchronized Block?

I personally have not had to use a sync. block to lock on another object other than this , but that is one use SOers point out about sync. blocks.

This totally does not matter from any efficiency point of view.

The point of having blocks is you can specify your own lock. You can choose a lock that is encapsulated within the object, as opposed to using this , with the consequence that you have more control over who can acquire the lock (since you can make that lock inaccessible from outside your object).

If you use this as the lock (whether you put synchronized on the method or use the block), anything in your program can acquire the lock on your object, and it's much harder to reason about what your program is doing.

Restricting access to the lock buys you a massive gain in decidability, it's much more beneficial to have that kind of certainty than to shave off a bytecode somewhere.

I know this might be an example, but if you plan on writing such code - think again.

To me it looks like you are duplicating information, and you should not do that unless you see that you need to do performance changes to your code. (Which you almost never should do).

  • If you really need this to be code that run in several threads, I'd make the nameList into a synchronized list using Collections.synchronizedList.
  • The last name should be a getter and it could pick the last element in the list.
  • The nameCount should be the size of the list.

If you do stuff like you have done now, you must also synchronize the access to all of the places where the variables are referenced, and that would make the code a lot less readable and harder to maintain.

You could remove all locking:

class Names {
  AtomicReference<Node> names = new AtomicReference<Node>();

  public void addName(final String name) {
    Node old = names.get();
    while (!names.compareAndSet(old, new Node(old, name))) {
      old = names.get();
    }
  }

  public String getName() {
    final Node node = names.get();
    return (node == null) ? null : node.name;
  }

  static class Node {
    final Node parent;
    final String name;

    Node(final Node parent, final String name) {
      this.parent = parent;
      this.name = name;
    }

    int count() {
      int count = 0;
      Node p = parent;
      while (p != null) {
        count++;
        p = p.parent;
      }
      return count;
    }
  }
}

This is basically a Treiber stack implementation. You can get the size, the current name, and you can easily implement an Iterator (albeit reverse to the one in your example) over the contents. Alternative copy-on-write containers could be used as well, depending on your needs.

Impossible to say, since the two code snippets arent equivalent.

The difference (the lack of synchronization of the call to add) may be significant, it might not be. From what you've given us its impossible to say.

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