1 ReentrantLock
它是一个可重入锁,即一个线程可重复加锁,即当前线程获取该锁再次获取不会被阻塞。获得几次锁,解锁也要解几次。
它有两种实现,公平锁和非公平锁。
- 公平锁:锁的获取顺序就应该符合请求上的绝对时间顺序
- 非公平锁:不按请求的时间,谁抢到就是谁的
默认实现的为非公平锁,因为公平锁为了保证时间上的绝对顺序,需要频繁的上下文切换,而非公平锁会降低一定的上下文切换,降低性能开销。
//创建一个公平锁
Lock lock = new ReentrantLock(true);
2 通过mysql进行实现
原理很简单,我们插入数据的时候都是只能插入一个唯一主键,如果有一个线程插入了,那么其他线程都不能插入了。
插入实体
package com.pibigstar.domain;
import javax.persistence.Entity;
import javax.persistence.Id;
@Entity
public class Mysql {
@Id
private int id;
public Mysql(int id) {
this.id = id;
}
//setter、getter方法
}
dao层:使用jpa
package com.pibigstar.dao;
import org.springframework.data.jpa.repository.JpaRepository;
import com.pibigstar.domain.Mysql;
public interface MysqlLockDao extends JpaRepository<Mysql, Integer>{
}
具体实现
package com.pibigstar.utils;
import java.util.Random;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import org.springframework.beans.factory.annotation.Autowired;
import com.pibigstar.dao.MysqlLockDao;
import com.pibigstar.domain.Mysql;
/**
* 基于mysql实现可重入锁
* @author pibigstar
*
*/
public class MysqlLock implements Lock{
@Autowired
private MysqlLockDao mysqlLockDao;
private static final Mysql my = new Mysql(1);
@Override
public void lock() {
//阻塞锁,不拿到资源不罢休
if (!tryLock()) {
try {
//如果没拿到,睡一下再拿
Thread.sleep(new Random().nextInt(10)+1);
} catch (InterruptedException e) {
}
lock();//继续调用自身拿锁
}
}
@Override
public boolean tryLock() {
//非阻塞锁,拿一次,拿到就拿到了,拿不到就撤
try {
mysqlLockDao.save(my);//插入成功即是拿到了
return true;
} catch (Exception e) {
//有异常说明已经被其他线程拿到了,
return false;
}
}
@Override
public void unlock() {
//解锁,将值删除即可
mysqlLockDao.delete(my);
}
@Override
public boolean tryLock(long time, TimeUnit unit) throws InterruptedException {
return false;
}
@Override
public void lockInterruptibly() throws InterruptedException {
}
@Override
public Condition newCondition() {
return null;
}
}