Interviewer: What are the differences between Synchronized and Lock interfaces?

Insert picture description here

Use of Lock interface

Now that there is synchronized, why do we need to provide a Lock interface? Maybe you would say that the Lock interface has higher performance than synchronized. This is true before jdk1.5, but after jdk1.6, the performance of the two is almost the same. Let's look directly at the definition of the Lock interface and see which functions are more than synchronized?

public interface Lock {
    
    

	// 加锁
    void lock();
	// 能够响应中断
    void lockInterruptibly() throws InterruptedException;
	// 非阻塞获取锁
    boolean tryLock();
	// 非阻塞超时获取锁
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
	// 解锁
    void unlock();
	// 定义阻塞条件
    Condition newCondition();
}

You can see that the Lock interface has many more features than synchronized. Explain the method in detail

  1. The lock() method is used to acquire the lock. If the lock is acquired by other threads, it will wait. It needs to cooperate with the unlock method to actively release the lock. When an exception occurs, the lock will not be released actively, so the operation of releasing the lock is placed in the finally block
  2. The lockInterruptibly() method, when the lock is acquired through this method, if the thread is waiting to acquire the lock, the thread can respond to the interrupt, that is, interrupt the waiting state of the thread. In other words, when two threads want to acquire a certain lock through lock.lockInterruptibly() at the same time, if thread A acquires the lock at this time, and thread B is only waiting, then call threadB.interrupt() method on thread B Able to interrupt the waiting process of thread B
  3. The tryLock() method is used to try to acquire the lock. If the acquisition is successful, it returns true. If the acquisition fails, it returns false. In other words, this method will return immediately anyway. I won’t wait forever when I can’t get the lock
  4. The tryLock(long time, TimeUnit unit) method is similar to tryLock(). The only difference is that this method will wait for a certain amount of time when the lock is not available, and if the lock is not available within the time limit, it will return false. If the lock is obtained at the beginning or during the waiting period, it returns true
  5. unlock() method, unlock
  6. newCondition() method, define conditions

The rest should be well understood, demonstrate the lockInterruptibly() and newCondition() methods

lockInterruptibly()方法

ReentrantLock myLock = new ReentrantLock();
// 先获取一次锁,让后续获取锁的操作阻塞
myLock.lock();
Thread thread = new Thread(() -> {
    
    
	try {
    
    
		// myLock.lock();
		myLock.lockInterruptibly();
	} catch (Exception e) {
    
    
		e.printStackTrace();
	} finally {
    
    
		// 当使用myLock.lockInterruptibly()时
		// 会抛出java.lang.InterruptedException,打印over
		// 使用myLock.lock(),一直阻塞获取锁,不会打印over
		System.out.println("over");
	}
});
thread.start();
TimeUnit.SECONDS.sleep(1);
thread.interrupt();
TimeUnit.SECONDS.sleep(100);

Use of Condition

The combination of synchronized and wait() and nitofy()/notifyAll() methods can realize the waiting/notification model. ReentrantLock can also be used, but it needs the help of Condition, and Condition has better flexibility, which is specifically reflected in

  1. Multiple Condition instances can be created in a Lock to achieve multiple notifications

  2. When the notify() method is used for notification, the notified thread is randomly selected by the Java virtual machine, but ReentrantLock combined with Condition can achieve selective notification

public class WaitNotify {
    
    

    static ReentrantLock lock = new ReentrantLock();
    static Condition conditionA  = lock.newCondition();
    static Condition conditionB = lock.newCondition();

    public static void main(String[] args) throws InterruptedException {
    
    
        Thread waitThreadA = new Thread(new WaitA(), "WaitThreadA");
        waitThreadA.start();
        Thread waitThreadB = new Thread(new WaitB(), "WaitThreadB");
        waitThreadB.start();
        TimeUnit.SECONDS.sleep(2);
        lock.lock();
        try {
    
    
            conditionA.signal();
        } finally {
    
    
            lock.unlock();
        }
    }

    static class WaitA implements Runnable {
    
    

        @Override
        public void run() {
    
    
            lock.lock();
            try {
    
    
                System.out.println(Thread.currentThread() + " begin await @ "
                        + new SimpleDateFormat("HH:mm:ss").format(new Date()));
                conditionA.await();
                System.out.println(Thread.currentThread() + " end await @ "
                        + new SimpleDateFormat("HH:mm:ss").format(new Date()));
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            } finally {
    
    
                lock.unlock();
            }
        }
    }

    static class WaitB implements Runnable {
    
    

        @Override
        public void run() {
    
    
            lock.lock();
            try {
    
    
                System.out.println(Thread.currentThread() + " begin await @ "
                        + new SimpleDateFormat("HH:mm:ss").format(new Date()));
                conditionB.await();
                System.out.println(Thread.currentThread() + " end await @ "
                        + new SimpleDateFormat("HH:mm:ss").format(new Date()));
            } catch (InterruptedException e) {
    
    
                e.printStackTrace();
            } finally {
    
    
                lock.unlock();
            }
        }
    }
}
Thread[WaitThreadA,5,main] begin await @ 00:49:57
Thread[WaitThreadB,5,main] begin await @ 00:49:57
Thread[WaitThreadA,5,main] end await @ 00:49:59

WaitThreadB has been blocked because it has not been notified

to sum up

Similarities and differences between synchronized and ReentrantLock

  1. ReentrantLock supports a non-blocking way to acquire locks and can respond to interrupts, but synchronized cannot
  2. ReentrantLock must manually acquire and release the lock, while synchronized does not require
  3. ReentrantLock can be a fair lock or an unfair lock, while synchronized can only be an unfair lock
  4. Synchronized will automatically release the lock held by the thread when an exception occurs, and when an exception occurs, ReentrantLock, if the lock is not released through unlock, it is likely to cause a deadlock, so you need to release the lock in the finally block
  5. Both synchronized and ReentrantLock are reentrant locks

Guess you like

Origin blog.csdn.net/zzti_erlie/article/details/112146823