java_锁_synchronized与Lock的区别
1、原始构成
synchronized是关键字,属于JVM层面;
monitorenter(底层是通过monitor对象完成,其实wait / notify等方法也依赖 monitor对象,只有在同步块或方法中才能调用wait / notify等方法);
monitorexit
Lock是具体的类(接口)(java.util.concurrent.locks.lock)是api层面的锁;
2、使用方法
synchronized不需要用户去手动释放锁,当synchronized代码执行完之后,系统会自动让线程释放对锁的占用;
ReentrantLock则需要用户手动去释放锁,若没有主动释放锁,就有可能导致出现死锁现象;需要lock()和unlock()方法来配置try/finally来使用;
3、等待是否可中断
synchronized不可中断,除非抛出异常或者正常运行完成
ReentrantLock可中断:
1、设置超时方法 tryLock(long time,TimeUnit unit)
2、当通过lockInterruptibly();进行加锁时,线程可通过调用interrupt();方法进行中断:
(lockInterruptibly()方法比较特殊,当通过这个方法去获取锁时,如果其他线程正在等待获取锁,则这个线程能够响应中断,即中断线程的等待状态。
也就使说,当两个线程同时通过lock.lockInterruptibly()想获取某个锁时,假若此时线程A获取到了锁,而线程B只有等待,
那么对线程B调用threadB.interrupt()方法能够中断线程B的等待过程。【注意是:等待的那个线程B可以被中断,不是正在执行的A线程被中断】)
4、加锁是否公平
synchronized:非公平锁
ReentrantLock:两者都可以,默认是非公平锁,构造方法可以传入boolean类型的值,true:公平锁,false:非公平锁;
5、锁绑定多个条件Condition
synchronized:没有
ReentrantLock:用来实现分组唤醒需要唤醒的线程们,可以精确唤醒,而不是像synchronized要么随机唤醒一个,要么全部唤醒;
编程题:(ReentrantLock绑定多个条件Condition,实现精确唤醒)
import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * 多线程之间按顺序调用 * 实现A-->B-->C三个线程启动 * A打印5次,B打印10次,C打印15次,来10轮 */ class ShareResource { private int number = 1;//A:1,B:2,C:3 private Lock lock = new ReentrantLock(); private Condition c1 = lock.newCondition(); private Condition c2 = lock.newCondition(); private Condition c3 = lock.newCondition(); /** * * @param str 当前调用的线程 * @param index 打印次数 */ public void print(String str,Integer index) { lock.lock();//加锁 try { if (str.equals("A")){ //1、判断 while (number != 1) {//当前不是 1(A),c1进行等待,则应该是 2(B)干活 c1.await(); } }else if (str.equals("B")){ while (number != 2) {//当前不是 2(B),c2进行等待,则应该是 3(C)干活 c2.await(); } }else if (str.equals("C")){ while (number != 3) {//当前不是 3(C),c3进行等待,则应该是 1(A)干活 c3.await(); } } //2、干活 System.out.print(Thread.currentThread().getName()+"\t"); for (int i = 1; i <= index; i++) { System.out.print("、"+i); } System.out.println(); //3、通知(唤醒) if (number == 1) {//如果当前是A在执行,则唤醒B number = 2; c2.signal(); } else if (number == 2) {//如果当前是B在执行,则唤醒C number = 3; c3.signal(); }else if (number == 3){//如果当前是C在执行,则唤醒A number = 1; c1.signal(); } } catch (Exception e) { e.printStackTrace(); } finally { lock.unlock();//解锁 } } } public class SynchronizedReentrantLockDemo { public static void main(String[] args) { ShareResource resource = new ShareResource(); new Thread(() -> { for (int i = 1; i <= 10; i++) { resource.print("A",5); } }, "A").start(); new Thread(() -> { for (int i = 1; i <= 10; i++) { resource.print("B",10); } }, "B").start(); new Thread(() -> { for (int i = 1; i <= 10; i++) { resource.print("C",15); } }, "C").start(); } }