实现分布式锁的步骤:
① 准备两张表(两张表的主键相同,利用mysql的唯一约束实现分布式锁),一张用来存任务,另一张存任务的锁
② 从任务表中获取要执行任务的数据信息
③ 向任务锁表中插入当前任务,若插入成功,则拿到了任务锁,可以执行任务,否则就不能执行任务
创建数据库表
# 创建任务表
create table if not exists `task`(id bigint primary key auto_increment comment '主键',description varchar(100) not null comment '任务描述'
);
# 创建任务锁表
create table if not exists `task_lock`(id bigint primary key comment '主键',description varchar(100) not null comment '任务描述'
);
# 添加任务
insert into `task`(id, description)
values(1,'说句hello world');
Java实体类
任务类
public class Task {private Long id;private String description;/*getter setter ...*/
}
任务锁类
public class TaskLock {private Long id;private String description;/*getter setter ...*/
}
mapper(直接继承的mybatisplus的BaseMapper)
public interface TaskMapper extends BaseMapper<Task> {
}
public interface TaskLockMapper extends BaseMapper<TaskLock> {
}
开启5000个线程模拟5000个服务去抢这一个任务资源
@SpringBootTest
public class LockTest {@Autowiredprivate TaskMapper taskMapper;@Autowiredprivate TaskLockMapper taskLockMapper;@Testvoid test_distributeLock_mysql() throws InterruptedException {Runnable run = () -> {// 获取id为1的任务信息Task task = taskMapper.selectById(1);// 向任务锁表中插入数据,若插入成功,代表拿到了锁,可以执行任务TaskLock taskLock = new TaskLock();taskLock.setId(task.getId());taskLock.setDescription(task.getDescription());try {taskLockMapper.insert(taskLock);// 拿到锁,执行打印任务System.out.println("hello world!");}catch (Exception e){// 未拿到锁}};List<Thread>threadPool = new ArrayList<>(5000);for (int i = 0; i < 5000; i++) {Thread thread = new Thread(run);thread.start();threadPool.add(thread);}for (Thread thread : threadPool) {thread.join();}}
}
执行结果:
可以看到5000个线程只有一个线程拿到了任务,执行完这个任务之后,其他线程也不会再次执行这个任务