【JUC】synchronizated和lock的区别&新lock的优势
原始构成
synchronized是关键字,属于JVM层面
javap -c 的结果显示
synchronized是可重入锁
11:是正常退出 17:是异常退出【保证不产生死锁和底层故障】
Lock是java.util.concurrent.locks包中的一个接口 是API层面的锁
使用方法
synchronized不需要手动释放锁,当synchronized代码执行完后系统自动让线程释放对锁的占用
ReentrantLock则需要用户手动释放没有主动释放的锁,可能出现死锁现象。需要lock、unlock和try/catch一起使用
等待是否可中断
synchronizated不可中断,除非抛出异常或者正常运行完成
reentrantLock可中高端
- 设置超时方法tryLock 【new ReentrantLock().tryLock(1,TimeUnit.SECONDS);】
- lockInterruptibly()放代码块中,调用interrupt()方法中断【new ReentrantLock().lockInterruptibly();】
是否是公平锁
synchronizated是非公平锁
reentrantLock源码:默认是非公平锁。也可以传参true为公平锁 false为非公平锁
1 /** 2 * Creates an instance of {@code ReentrantLock}. 3 * This is equivalent to using {@code ReentrantLock(false)}. 4 */ 5 public ReentrantLock() { 6 sync = new NonfairSync(); 7 } 8 9 /** 10 * Creates an instance of {@code ReentrantLock} with the 11 * given fairness policy. 12 * 13 * @param fair {@code true} if this lock should use a fair ordering policy 14 */ 15 public ReentrantLock(boolean fair) { 16 sync = fair ? new FairSync() : new NonfairSync(); 17 }
锁是否绑定多个条件Condition
synchronizated没有,只能随机唤醒一个(notify()),或者唤醒全部唤醒(notifyAll())
ReentrantLock用来实现分组唤醒需要唤醒的线程,可以精确唤醒某个线程。
例如:多线程之间按顺序调用 实现线程之间按顺序启动【精确唤醒的举例】
1 import java.util.concurrent.locks.Condition; 2 import java.util.concurrent.locks.Lock; 3 import java.util.concurrent.locks.ReentrantLock; 4 5 /** 6 * 一个拍照的景点 有3个人要按顺序排单人照 7 * 张三想要拍1张 李四想要拍3张 王五想要拍5张 8 * 他们按照这个顺序排了两个景点 9 */ 10 class Plat{ 11 private int id = 1; // 3人的编号 12 private Lock lock = new ReentrantLock(); 13 private Condition person1 = lock.newCondition(); 14 private Condition person2 = lock.newCondition(); 15 private Condition person3 = lock.newCondition(); 16 public void person1TakePhoto(){ 17 lock.lock(); 18 try{ 19 while (id != 1){ 20 person1.await(); 21 } 22 for (int i = 0; i < 1; i++) { 23 System.out.println(Thread.currentThread().getName()+ "拍了"+(i+1)+"张照片"); 24 } 25 id = 2; 26 person2.signal(); 27 }catch(Exception e){ 28 e.printStackTrace(); 29 }finally{ 30 lock.unlock(); 31 } 32 } 33 public void person2TakePhoto(){ 34 lock.lock(); 35 try{ 36 while (id != 2){ 37 person2.await(); 38 } 39 for (int i = 0; i < 3; i++) { 40 System.out.println(Thread.currentThread().getName()+ "拍了"+(i+1)+"张照片"); 41 } 42 id = 3; 43 person3.signal(); 44 }catch(Exception e){ 45 e.printStackTrace(); 46 }finally{ 47 lock.unlock(); 48 } 49 } 50 public void person3TakePhoto(){ 51 lock.lock(); 52 try{ 53 while (id != 3){ 54 person3.await(); 55 } 56 for (int i = 0; i < 5; i++) { 57 System.out.println(Thread.currentThread().getName()+ "拍了"+(i+1)+"张照片"); 58 } 59 id = 1; 60 person1.signal(); 61 }catch(Exception e){ 62 e.printStackTrace(); 63 }finally{ 64 lock.unlock(); 65 } 66 } 67 68 } 69 public class ReentantLockTest { 70 public static void main(String[] args) throws InterruptedException { 71 Plat plat = new Plat(); 72 new Thread(()->{ 73 for (int i = 0; i < 2; i++) { 74 plat.person1TakePhoto(); 75 } 76 },"张三").start(); 77 new Thread(()->{ 78 for (int i = 0; i < 2; i++) { 79 plat.person2TakePhoto(); 80 } 81 },"李四").start(); 82 new Thread(()->{ 83 for (int i = 0; i < 2; i++) { 84 plat.person3TakePhoto(); 85 } 86 },"王五").start(); 87 } 88 }
输出结果:
张三拍了1张照片
李四拍了1张照片
李四拍了2张照片
李四拍了3张照片
王五拍了1张照片
王五拍了2张照片
王五拍了3张照片
王五拍了4张照片
王五拍了5张照片
张三拍了1张照片
李四拍了1张照片
李四拍了2张照片
李四拍了3张照片
王五拍了1张照片
王五拍了2张照片
王五拍了3张照片
王五拍了4张照片
王五拍了5张照片