The difference between Lock and synchronized

Of course, the implementation of synchronization adopts locks. The two basic tools for using locks in java are synchronized and Lock.

// Unsynchronized method
public void test() {}
// Synchronization method
pubilc synchronized void test() {}
synchronized It can also be used in a code block. Look
public void test() {
     synchronized(obj) {
          System.out.println("===");
     }
}

What's the difference between synchronized for methods and code blocks?

Synchronized is used on the method name. When a thread calls this method, it will obtain the object lock of the instance. Before the method ends, other threads can only wait. The object lock will not be released until this method is executed. Only other threads have the opportunity to seize the lock and execute the method, but the basis of all this should be the same object instance used by all threads in order to realize mutual exclusion. Otherwise, the synchronized keyword is meaningless.

(however, if the method is a class method, that is, its modifier is static, then synchronized
This means that a thread calling this method currently owns the lock of this class. As long as the thread continues to run in the current method, other threads still cannot obtain the right to use the method!)

How synchronized is used in code blocks: synchronized(obj){//todo code here}

When a thread runs into the code block, it will own the Object lock of the obj Object. If multiple threads share the same Object object, mutual exclusion will be formed at this time! In particular, when obj == this, it represents the instance Object that currently calls the method.

public void test() {
     ...
     synchronized(this) {
          // todo your code
     }
     ...
}

At this point, the effect is equivalent to

public synchronized void test() {
     // todo your code
}

Using synchronized code blocks, you can synchronize only the code that needs to be synchronized, which can greatly improve efficiency.

Summary:

There are two advantages over using synchronized code blocks:

1. You can use only those that need synchronization

2. It is more convenient when used with wait()/notify()/nitifyAll()

In addition to wait() and notify() cooperating to complete thread synchronization, Lock can also accomplish the same purpose.

ReentrantLock has the same concurrency and memory semantics as synchronized. It also includes interrupt lock waiting and timed lock waiting, which means that if thread A obtains the lock of object obj first, thread B can still not obtain the lock within the specified waiting time, and the lock will be automatically discarded.

However, because synchronized is implemented at the JVM level, the system can monitor whether the lock is released or not. However, ReentrantLock is implemented in code, and the system cannot automatically release the lock. lock.unlock() needs to be explicitly released in the finally clause of the code;

public class Consumer implements Runnable {
 
     private Lock lock;
     public Consumer(Lock lock) {
            this. lock = lock;
     }
     @Override
     public void run() {
            // TODO Auto-generated method stub
            int count = 10;
            while( count > 0 ) {
                 try {
                      lock.lock();
                     count --;
                     System. out.print( "B");
                } finally {
                      lock.unlock(); //Active release lock
                      try {
                           Thread. sleep(91L);
                     } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                           e.printStackTrace();
                     }
                }
           }
 
     }
 
}
 
public class Producer implements Runnable{
 
     private Lock lock;
     public Producer(Lock lock) {
            this. lock = lock;
     }
     @Override
     public void run() {
            // TODO Auto-generated method stub
            int count = 10;
            while (count > 0) {
                 try {
                      lock.lock();
                     count --;
                     System. out.print( "A");
                } finally {
                      lock.unlock();
                      try {
                           Thread. sleep(90L);
                     } catch (InterruptedException e) {
                            // TODO Auto-generated catch block
                           e.printStackTrace();
                     }
                }
           }
     }
}
 
//Calling code:
 
public class Test {
 
     public static void main(String[] args) {
           Lock lock = new ReentrantLock();
           
           Consumer consumer = new Consumer(lock);
           Producer producer = new Producer(lock);
           
            new Thread(consumer).start();
            new Thread( producer).start();
           
     }
}

Suggestions for use:

When the concurrency is small, using synchronized is a good choice, but when the concurrency is high, its performance degrades seriously. At this time, ReentrantLock is a good scheme.

Tags: Java lock

Posted on Fri, 24 Sep 2021 03:16:52 -0400 by Nik