synchronized 是关键字属于 JVM 层面,反应在字节码上是 monitorenter 和 monitorexit,其底层是通过 monitor 对象来完成,其实 wait/notify 等方法也是依赖 monitor 对象只有在同步快或方法中才能调用 wait/notify 等方法。 Lock 是具体类(java.util.concurrent.locks.Lock)是 api 层面的锁。
synchronized 不需要用户手动去释放锁,当 synchronized 代码执行完后系统会自动让线程释放对锁的占用。 ReentrantLock 则需要用户手动的释放锁,若没有主动释放锁,可能导致出现死锁的现象,lock() 和 unlock() 方法需要配合 try/finally 语句来完成。
synchronized 不可中断,除非抛出异常或者正常运行完成。 ReentrantLock 可中断,设置超时方法 tryLock(long timeout, TimeUnit unit),lockInterruptibly() 放代码块中,调用 interrupt() 方法可中断。
synchronized 非公平锁 ReentrantLock 默认非公平锁,构造方法中可以传入 boolean 值,true 为公平锁,false 为非公平锁。
锁可以绑定多个 Condition synchronized 没有 Condition。 ReentrantLock 用来实现分组唤醒需要唤醒的线程们,可以精确唤醒,而不是像 synchronized 要么随机唤醒一个线程要么唤醒全部线程。 demo:使用一个number作为标志位,3个condition精确唤醒
class ShareSource{ private int number = 1;//A1B2C3 private Lock lock = new ReentrantLock(); private Condition condition1 = lock.newCondition(); private Condition condition2 = lock.newCondition(); private Condition condition3 = lock.newCondition(); public void print5() { lock.lock(); try { while(number != 1) { condition1.await(); } for(int i = 1; i <= 5; i++) { System.out.println(Thread.currentThread().getName()+i); } number = 2; condition2.signal(); } catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); } } public void print10() { lock.lock(); try { while(number!=2) { condition2.await(); } for (int i = 0; i < 10; i++) { System.out.println(Thread.currentThread().getName()+i); } number = 3; condition3.signal(); } catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); } } public void print15() { lock.lock(); try { while(number != 3) { condition3.await(); } for(int i =0 ; i < 15; i++) { System.out.println(Thread.currentThread().getName()+i); } number = 1; condition1.signal(); } catch (Exception e) { e.printStackTrace(); }finally { lock.unlock(); } } } public class Syn_vs_LockDemo { public static void main(String[] args) { ShareSource shareSource = new ShareSource(); new Thread(()->{ for(int i =0 ; i < 10; i++) { shareSource.print5(); } },"A").start(); new Thread(()->{ for(int i =0 ; i < 10; i++) { shareSource.print10(); } },"B").start(); new Thread(()->{ for(int i =0 ; i < 10; i++) { shareSource.print15(); } },"C").start(); } }