锁:synchronized 能够在同一时刻最多只有一个线程执行该段代码,以达到并发安全的效果
操作共享数据的代码,极为需要同步的代码
共享数据:多个线程共同操作的变量
同步监视器:俗称 锁,任何一个对象都可以当锁
要求:多个线程必要要共用同一把锁
同步的方式,解决了线程的安全问题,(好处)
操作同步代码时,只能有一个线程参与,其他线程等待,相当于是一个单线程的过程(坏处)
Java.util.concurrent.locks Lock接口是控制多个线程对共享资源进行访问的工具,锁提供了对共享资源独占访问,每次只能有一个Lock对象加锁,线程开始访问共享资源之前应先获得Lock对象
ReentrantLock 类实现了Lock ,它拥有与synchronized 相同的并发性和内存语音,在实现线程安全的控制中,比较常用的是ReentrantLock 可以显式加锁,释放锁
synchronized 与 Lock的对比
1,Lock是显式锁(手动开启和关闭锁,别忘记关闭锁),synchronized 是隐式锁,出了作用域自动释放
2,Lock只有代码块锁,synchronized 有代码块锁和方法锁
3,使用Lock锁,JVM将花费较少的时间来调度线程,性能更好而且更具有更好的扩展性(提供更多的子类)
优先使用顺序
Lock -> 同步代码块(已经进入了方法体,分配了相应资源)->同步方法(在方法体之外)
面试题:synchronized与Lock的区别
1, synchronized是关键字,而Lock是一个接口。
2. synchronized会自动释放锁,而Lock必须手动释放锁。
3. synchronized是不可中断的,Lock可以中断也可以不中断。
4. 通过Lock可以知道线程有没有拿到锁,而synchronized不能。
5. synchronized能锁住方法和代码块,而Lock只能锁住代码块。
6. Lock可以使用读锁提高多线程读效率。
7. synchronized是非公平锁,ReentrantLock可以控制是否是公平锁。
wait():一旦执行此方法,当前线程就进入阻塞状态,并释放同步监视器。
notify():一旦执行此方法,就会唤醒被wait的一个线程。如果有多个线程被wait,就唤醒优先级高的那个。
notifyAll():一旦执行此方法,就会唤醒所有被wait的线程。
说明:
1.wait(),notify(),notifyAll()三个方法必须使用在同步代码块或同步方法中。
2.wait(),notify(),notifyAll()三个方法的调用者必须是同步代码块或同步方法中的同步监视器。 否则,会出现IllegalMonitorStateException异常
3.wait(),notify(),notifyAll()三个方法是定义在java.lang.Object类中。
面试题:sleep() 和 wait()的异同?
1.相同点:一旦执行方法,都可以使得当前的线程进入阻塞状态。
2.不同点:
1)两个方法声明的位置不同:Thread类中声明sleep() , Object类中声明wait()
2)调用的要求不同:sleep()可以在任何需要的场景下调用。 wait()必须使用在同步代码块或同步方法中
3)关于是否释放同步监视器:如果两个方法都使用在同步代码块或同步方法中,sleep()不会释放锁,wait()会释放锁。