目录
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.IllegalMonitorStateException
at 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 zero
at 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博客