目录
1. lock 基本用法
2. lock公平锁与非公平锁
3. lock注意事项
4. synchronized 与 lock区别
1. lock 基本用法
lock.lock();
try {} finally {lock.unlock()
}或者try {lock.lock();
} finally {lock.unlock()
}public class ThreadLock1 {public static void main(String[] args) {//1. 创建锁对象Lock lock = new ReentrantLock();//2. 加锁lock.lock();try{System.out.println("你好");}finally {// 3. 释放锁lock.unlock(); }}
}输出:
你好
注意:lock要放到try外,或者try里面的第一行。
原因有两个:
1. 如果放在 try ⾥⾯,因为 try 代码中的异常导致加锁失败,还会执⾏ finally 释放锁的操作。
2. unlock 异常会覆盖 try ⾥⾯的业务异常,增加排查错误的难度。
2. lock公平锁与非公平锁
非公平锁:
public class ThreadLock2 {private static int number = 0;static class Counter {//1. 创建锁对象private static Lock lock = new ReentrantLock();//循环次数private static int MAX_COUNT = 1000000;public static void incr() {for (int i = 0; i < MAX_COUNT; i++) {lock.lock();try {number++;} finally {lock.unlock();}}}public static void decr() {for (int i = 0; i < MAX_COUNT; i++) {lock.lock();try {number--;} finally {lock.unlock();}}}}public static void main(String[] args) throws InterruptedException {long stime = System.currentTimeMillis();Thread t1 = new Thread(() ->{Counter.incr();});t1.start();Thread t2 = new Thread(() ->{Counter.decr();});t2.start();t1.join();t2.join();long etime = System.currentTimeMillis();System.out.println("最终结果:" + number + " 执行时间:" + (etime - stime));}
}输出:
最终结果:0 执行时间:172
公平锁
修改:private static Lock lock = new ReentrantLock(true);输出:
最终结果:0 执行时间:5382
可以明显看出非公平锁比公平锁性能好很多。
3. lock注意事项
1. unlock操作一定要在finally里面。
会出现的问题:可能会导致锁资源永久占用的问题。
2. lock() 一定要放在try之前,或者是try的首行。
会出现问题:a. 未加锁却执行了释放锁的操作。 b. 释放锁的错误信息会覆盖业务报错信息,从而增加调试程序和修复程序的复杂度。
public class ThreadLock4 {public static void main(String[] args) {Lock lock = new ReentrantLock();try {System.out.println("进入了 try 方法");int i = 10 / 0; // 某一种极端的操作System.out.println("执行 lock 操作");lock.lock();} finally {System.out.println("执行 unlock 操作");lock.unlock();}}
}输出:进入了 try 方法执行 unlock 操作Exception in thread "main" java.lang.IllegalMonitorStateExceptionat java.util.concurrent.locks.ReentrantLock$Sync.tryRelease(ReentrantLock.java:151)at java.util.concurrent.locks.AbstractQueuedSynchronizer.release(AbstractQueuedSynchronizer.java:1261)at java.util.concurrent.locks.ReentrantLock.unlock(ReentrantLock.java:457)at thread.ThreadLock4.main(ThreadLock4.java:24)
public class ThreadLock4 {public static void main(String[] args) {Lock lock = new ReentrantLock();System.out.println("执行 lock 操作");lock.lock();try {System.out.println("进入了 try 方法");int i = 10 / 0; // 某一种极端的操作} finally {System.out.println("执行 unlock 操作");lock.unlock();}}
}输出:执行 lock 操作进入了 try 方法执行 unlock 操作Exception in thread "main" java.lang.ArithmeticException: / by zeroat thread.ThreadLock4.main(ThreadLock4.java:20)
4. synchronized 与 lock区别
1. Lock更灵活,有更多的方法。比如,try lock()......
2. Lock默认是非公平锁,但可以指定为公平锁;synchronized只能为非公平锁。
3. 调用lock方法和synchronized线程等待锁状态不同,lock方法会变味WAITING,而synchronized会变为BLOCKED。
4. synchronized是JVM层面提供的锁,它是自定进行加锁和释放锁,对于开发者来说是无感的;而lock需要开发者自己进行加锁和释放锁的操作。
5. synchronized可以修改方法(静态方法/普通方法) 和代码块;而lock只能修饰代码块。
lock等待时,WAITING状态:public class ThreadLock5 {public static void main(String[] args) throws InterruptedException {Lock lock = new ReentrantLock();System.out.println("执行lock操作");Thread t1 = new Thread(() -> {lock.lock();System.out.println("线程1得到锁");try{Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}finally {System.out.println("线程1释放锁");lock.unlock();}});t1.start();Thread t2 = new Thread(() -> {try{Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}lock.lock();try {System.out.println("线程2得到锁");}finally {System.out.println("线程2释放锁");lock.unlock();}});t2.start();Thread.sleep(1500);System.out.println("线程2: " + t2.getState());t1.join();t2.join();}
}
输出:
执行lock操作
线程1得到锁
线程2: WAITING
线程1释放锁
线程2得到锁
线程2释放锁
public class ThreadLock6 {public static void main(String[] args) throws InterruptedException {System.out.println("执行synchronized操作");Thread t1 = new Thread(() -> {synchronized (ThreadLock6.class) {System.out.println("线程1得到锁");}try{Thread.sleep(3000);} catch (InterruptedException e) {e.printStackTrace();}});t1.start();Thread t2 = new Thread(() -> {try{Thread.sleep(1000);} catch (InterruptedException e) {e.printStackTrace();}synchronized (ThreadLock6.class) {System.out.println("线程2得到锁");}});t2.start();Thread.sleep(1500);System.out.println("线程2: " + t2.getState());t1.join();t2.join();}
}输出:
执行synchronized操作
线程1得到锁
线程2得到锁
线程2: TERMINATED
synchronized 讲解:
synchronized_Youcan.的博客-CSDN博客