文章目录
需求: 同一个订单才加同步锁,不同订单可并行
synchronized
synchronized是Java中的关键字,是一种同步锁,是原生语法层面的互斥,需要jvm实现。它修饰的对象有以下几种:
1. 修饰一个代码块,被修饰的代码块称为同步语句块,其作用的范围是大括号{}括起来的代码,作用的对象是调用这个代码块的对象;
2. 修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
3. 修改一个静态的方法,其作用的范围是整个静态方法,作用的对象是这个类的所有对象;
4. 修改一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。
synchronized 作用当前对象
测试效果:
一)线程1 与 线程2 ,结果 线程1结束了线程2才开始。
synchronized 作用订单号条件
测试效果:
一)线程1 与 线程2 ,结果 线程1线程2可以同时开始。
二)线程1 与 线程1 ,结果 线程1与另一个线程1同时开始
。
synchronized 的锁不是比较字符串,而是对象,所以每次请求进来的orderId不是同一个对象。
synchronized 作用订单号字符串条件
把 synchronized 锁的 orderId 放在常量池中,那每次请求进来的就是同一个对象。
测试效果:
一)线程1 与 线程1 ,结果 线程1线程1锁住了。
二)线程1 与 线程2,结果 线程1与线程2同时开始。
ReentrantLock 加 ConcurrentHashMap
ReentrantLock它是JDK 1.5之后提供的API层面的互斥锁,需要lock()和unlock()方法配合try/finally语句块来完成
------------------------------------------------controller
@RestController
public class OrderController{
@Autowired
SynchronizedByKey synchronizedByKey;
@ResponseBody
@RequestMapping("")
pubilc Map<String,Object> process(@PathVariable("orderId")String orderId){
SynchronizedByKey.exec(orderId,() ->{
logger.debug("[{}] 开始",orderId);
logger.debug("[{}] 结束",orderId);
});
}
}
------------------------------------------------SynchronizedByKey
public class SynchronizedByKey {
Map<String,ReentrantLock> mutexCache = new ConcurrentHashMap<>;
public void exec(String key,Runnable statement){
ReentrantLock mutex4Key = null;
ReentrantLock mutexInCache;
do{
if(mutex4Key != null){
mutex4Key.unlock();
}
mutex4Key = mutexCache.computeIfAbsent(key, k -> new ReentrantLock());
mutex4Key.lock();
/* lock()后再根据key去mutexCache取一把锁(mutexInCache),
极端情况:
1.我刚刚拿到了这把锁(mutexInCache),又从map里取的时候它为空了,说明我刚刚拿到的那么锁被remove掉了;
2.我刚刚拿到了这把锁(mutexInCache),被新进来的线程(都是001)又创建了一把新锁覆盖了,
所以mutex4Key 和 mutexInCache 不等; */
mutexInCache = mutexCache.get(key);
} while(mutexInCache == null || mutex4Key != mutexInCache);
try{
statement.run();
} finally{
if(mutex4Key.getQueueLength() == 0){
mutexCache.remove(key);
}
mutex4Key.unlock();
}
}
}
@Override
public ResultMessage<Object> imgAndVideoHandler(TaskImgVideoParams taskImgVideoParams, String accessToken) {
AuthUser authUser = UserContext.getAuthUser(cache, accessToken);
//如果用户未登录,则无法上传图片
if (authUser == null) {
throw new ServiceException(ResultCode.USER_AUTHORITY_ERROR);
}
if (taskImgVideoParams.getFile().isEmpty() || taskImgVideoParams.getFile().getSize() <= 0) {
return ResultUtil.error(ResultCode.LEADER_PHOTO_VIDEO_NULL_ERROR);
}
String descriptionId;
List<PhotoAndVideo> photoVideoByGroupId = null;
//String groupId = taskImgVideoParams.getGroupId().intern();
synchronized (this) {
photoVideoByGroupId = getPhotoVideoByGroupId(taskImgVideoParams.getGroupId());
if (photoVideoByGroupId.size() < 1) {
Description description = new Description(taskImgVideoParams.getContent(), taskImgVideoParams.getLeaderId(),
taskImgVideoParams.getTaskDay(), taskImgVideoParams.getReceiveTaskId());
boolean saveDescription = descriptionService.save(description);
if (!saveDescription) {
return ResultUtil.error(ResultCode.LEADER_SAVE_PHOTO_VIDEO_DESCRIPTION_ERROR);
}
descriptionId = description.getId();
} else {
descriptionId = photoVideoByGroupId.get(0).getDescriptionId();
}
String url = "";
try {
url = fileBuyerService.writeFile(taskImgVideoParams.getFile(), "F:\\IMAGES", "IMAGES");
} catch (IOException e) {
e.printStackTrace();
fileBuyerService.deleteFile(url, "F:\\IMAGES");
if (photoVideoByGroupId.size() > 1) {
for (PhotoAndVideo photoVideo : photoVideoByGroupId) {
fileBuyerService.deleteFile(photoVideo.getUrl(), "F:\\IMAGES");
}
}
deleteByGroupId(taskImgVideoParams.getGroupId());
descriptionService.removeById(descriptionId);
return ResultUtil.error(ResultCode.LEADER_SAVE_PHOTO_VIDEO_ERROR);
}
PhotoAndVideo photoAndVideo = new PhotoAndVideo(url, taskImgVideoParams.getOrder(), taskImgVideoParams.getGroupId(), descriptionId);
boolean savePhotoAndVideo = this.save(photoAndVideo);
if (!savePhotoAndVideo) {
deleteByGroupId(taskImgVideoParams.getGroupId());
descriptionService.removeById(descriptionId);
return ResultUtil.error(ResultCode.LEADER_SAVE_PHOTO_VIDEO_ERROR);
}
return ResultUtil.success();
}
}