1.官方文档简介
2.可重入锁
广义上的可重入锁指的是可重复可递归调用的锁,在外层使用锁之后,在内层仍然可以使用,并且不发生死锁(前提得是同一个对象或者class),这样的锁就叫做可重入锁。
实现可重入锁代码:
public class ReentrantTest implements Runnable {
public synchronized void get() {
System.out.println(Thread.currentThread().getName());
set();
}
public synchronized void set() {
System.out.println(Thread.currentThread().getName());
}
public void run() {
get();
}
public static void main(String[] args) {
ReentrantTest rt = new ReentrantTest();
for(;;){
new Thread(rt).start();
}
}
}
2.什么是lock锁
LOCK锁实现提供了比使用同步方法和语句可以获得的更广泛的锁操作。它们允许更灵活的结构。可能具有非常不同的属性,并且可能支持多个关联的条件对象。Lock提供了比sychronized更多的功能。
Lock与synchronized区别
- syncgronized是java内置的,而在jvm层面,lock是个java类
- synchronized会自动释放锁(执行完同步代码块会释放锁,发生异常会释放锁),Lock需在finally中手工释放锁(unlock方法释放),否则容易造成线程死锁
- synchronized给两个线程a,b上锁,a线程阻塞了,b线程就会一直等待下去(即自旋),而lock就不一定会等待下去,如果尝试获取不到锁,不会自旋或等待直接就会结束
- synchronized的锁可重入,不可中断,非公平,而lock锁可重入、可中断、可公平(两者皆可)
- lock适合大量同步代码块,synchronize适合少量同步代码块
3.使用lock实现卖票案例
资源类
public class LTicket {
//票数量
private int number = 1000;
//创建可重入锁
private final ReentrantLock lock = new ReentrantLock();
//卖票方法
public void sale(){
//上锁
lock.lock();
try{
//判断是否有票
if(number > 0){
System.out.println(Thread.currentThread().getName()+"::卖出"+(number--)+"剩余:"+number);
}
}finally {
//解锁
lock.unlock();
}
}
}
创建多个线程使用资源类
public class LSaleTicket {
public static void main(String[] args) {
LTicket ticket = new LTicket();
new Thread(()->{
for (int i = 0 ; i < 1000 ;i++){
ticket.sale();
}
},"aa").start();
new Thread(()->{
for (int i = 0 ; i < 1000 ;i++){
ticket.sale();
}
},"bb").start();
new Thread(()->{
for (int i = 0 ; i <1000 ;i++){
ticket.sale();
}
},"cc").start();
}
}