一、锁是什么?
我们都知道,在多线程的环境下,是会引发线程安全的问题的,那么针对这一问题,java提供了synchronized和lock锁机制来控制线程的并发访问,简单来说锁是用来防止多线程操作同一段资源,以防止出现错误的执行结果。
那下面来讲简单介绍一下两种锁的使用方式吧!
二、使用步骤
1.synchronized
以卖票为例子:
package com.lhh.demo;
/**
*
* @param
* @author HaiHui
* @date 2021/1/29 10:35
* @return
*/
public class Tickle1 {
private int number = 30;
public synchronized void sale() {
//业务代码
if (number > 0) {
//引入两行代码是为了检测假如不加synchronized会造成怎样的后果。
System.out.println(Thread.currentThread().getName() + "卖出了" + (number--) + "票,剩余" + number);
System.out.println(Thread.currentThread().getName());
}
}
}
2.lock
我们还是以卖票为例:
- 创建ReteenLock对象
- lock加锁
- 中间是业务代码
- unlock解锁
package com.lhh.demo;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
*
* 使用Lock三部曲
* 1.创建ReteenLock对象
* 2.lock.lock() 加锁
* 3.lock.unlock() 解锁
* @author HaiHui
* @date 2021/1/29 10:35
* @param
* @return
*/
public class Tickle {
private int number = 30;
Lock lock = new ReentrantLock();//可重入锁
public void sale() {
lock.lock();/*开启锁*/
try {
//业务代码
if (number > 0) {
System.out.println(Thread.currentThread().getName() + "卖出了" + (number--) + "票,剩余" + number);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();/*解锁,必须配对,假如有多个lock.lock()操作,那么就需要多次解锁。*/
}
}
}
接下来,我们测试一下卖票的过程:
package com.lhh.demo;
public class TickleDemo {
public static void main(String[] args) {
//多线程操作统一资源Tickle,并发编程的要求,把tickle资源丢入线程即可。
Tickle tickle = new Tickle();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
tickle.sale();
}
}, "A").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
tickle.sale();
}
}, "B").start();
new Thread(() -> {
for (int i = 0; i < 10; i++) {
tickle.sale();
}
}, "C").start();
}
}
声明一点,这里不是按照abc的顺序执行是因为可重入锁ReteenLock的构造方法没有加true参数,默认就是非公平锁,cpu默认随机切换线程执行,如果指定为true的话,那么就是按照严格的顺序执行了,必须是一个线程执行完毕之后释放锁,后面的线程才能被执行。
三、总结
区别:
相同点:
- 他们都是重入锁
- 他们都可以用来控制多线程环境下的线程安全问题
不同点:
- synchronized是一个关键字,而lock是一个java类
- synchronized无法获取锁的状态,而lock可以做到
- synchronized可以自动释放锁,而lock需要手动释放,不释放会死锁
- synchronized适合少量的代码同步代码,而lock释放大量的同步代码
- synchronized可能引发线程无线等待(拿到锁的线程突然由于某种原因阻塞了,那么造成后面需要该锁的线程一直无限期的等待下去),而lock不一定