Explicit and implicit locks refer mainly to the synchronized keyword and the ReentrantLock class.

Let’s talk about the differences between the two:

1 Different Bottom layer

Synchronized is a Java keyword and a LOCK at the JVM level.

ReentrantLock is a concrete class that has emerged since JDK5. Using lock calls the corresponding API.

Let’s look at the assembly instructions that call both using the Javap command:

You can see that synchronized is the underlying monitorenter lock and monitorexit lock.

ReentrantLock objects acquire and release locks by calling the corresponding API methods.

2 Different use modes

As the title of this article suggests, the biggest difference between explicit and implicit locks is whether programmers have to manually write code to acquire and release locks when they are used.

With the synchronized keyword, we users don’t have to write any additional code at all, and the program can acquire and release the lock. That’s because the system automatically tells the program to release the lock once the synchronized block is complete. As follows:

public class Demo9 {
    public static void main(String[] args) {
        // The thread is not safe
        // Solution 2 Synchronization method
        Runnable runnable = new Ticket();
        new Thread(runnable).start();
        new Thread(runnable).start();
        new Thread(runnable).start();
    }

    static class Ticket implements Runnable{
        / / total votes
        private int count = 10;
        @Override
        public void run(a) {
            while (true) {
                boolean flag = sale();
                if(! flag){break; }}}public synchronized boolean sale(a){
            if (count > 0) {
                / / tickets
                System.out.println("Preparing to sell tickets.");
                try {
                    Thread.sleep(1000);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                count--;
                System.out.println(Thread.currentThread().getName()+"End of sale, remaining tickets:" + count);
                return true;
            }
                return false; }}}Copy the code

When using the lock, we users need to manually acquire and release the lock. If the lock is not released, a deadlock can occur.

  • Manual lock acquisition method:
lock.lock();
Copy the code

  • Manually release lock:
lock.unlock();
Copy the code

Examples are as follows:

public class Demo10 {
    public static void main(String[] args) {
        Runnable run = new Ticket();
        new Thread(run).start();
        new Thread(run).start();
        new Thread(run).start();
    }

    static class Ticket implements Runnable{
        / / total votes
        private int count = 10;
        private Lock l = new ReentrantLock();
        @Override
        public void run(a) {
            while (true) {
                l.lock();
                    if (count > 0) {
                        / / tickets
                        System.out.println("Preparing to sell tickets.");
                        try {
                            Thread.sleep(1000);
                        } catch (InterruptedException e) {
                            e.printStackTrace();
                        }
                        count--;
                        System.out.println(Thread.currentThread().getName()+"End of sale, remaining tickets:" + count);
                    }else {
                        break; } l.unlock(); }}}}Copy the code

3 Check whether the service can be interrupted

Synchronized is uninterruptible. Unless an exception is thrown or normal operation completes

Lock can be broken. Interrupt mode:

  • Calling lockInterruptibly() into a block of code and then calling the interrupt() method can interrupt it

4 Check whether the lock is fair

Synchronized is an unfair lock

When creating a lock, you can pass in a Boolean value to set whether the lock is fair or not:

  • True: fair lock
  • False: unfair lock

5 performance

Prior to java1.6, synchronized performance was lower because it required an operation interface to be invoked, potentially consuming more system time than operations other than locking. Lock performance was higher in comparison.

However, after java1.6, locks have been optimized a lot, and lightweight locks, biased locks, lock elimination and adaptive spin locks have emerged, leading to good performance of synchronized, and it is more officially supported because of its clear semantics.

6 Lock mode

Lock The process of acquiring and releasing locks requires manual control by the programmer. Lock uses optimistic locking.

  • Optimistic locking: An operation is performed each time without locking, assuming no conflicts, and if it fails because of conflicts, retry until it succeeds.

Synchronized hosts JVM execution using the CPU pessimistic locking mechanism originally

  • Pessimistic lock: the thread obtains an exclusive lock. An exclusive lock means that other threads must rely on blocking to wait for the thread to release the lock.