简要说明:

表设计时,需要往表里加一个version字段。每次查询时,查出带有version的数据记录更新数据时,判断数据库里对应id的记录的version是否和查出的version相同。若相同,则更新数据并把版本号+1;若不同,则说明,该数据发送并发,被别的线程使用了,进行递归操作,再次执行递归方法,知道成功更新数据为止

简单说说乐观锁。乐观锁是相对于悲观锁而言。悲观锁认为,这个线程,发生并发的可能性极大,线程冲突几率大,比较悲观。一般用synchronized实现,保证每次操作数据不会冲突。乐观锁认为,线程冲突可能性小,比较乐观,直接去操作数据,如果发现数据已经被更改(通过版本号控制),则不更新数据,再次去重复 所需操作,知道没有冲突(使用递归算法)。

因为乐观锁使用递归+版本号控制  实现,所以,如果线程冲突几率大,使用乐观锁会重复很多次操作(包括查询数据库),尤其是递归部分逻辑复杂,耗时和耗性能,是低效不合适的,应考虑使用悲观锁。

乐观锁悲观锁的选择:

乐观锁:并发冲突几率小,对应模块递归操作简单    时使用

悲观锁:并发几率大,对应模块操作复杂 时使用

案例一

	/**
* 自动派单
* 只查出一条 返回list只是为了和查询接口统一
* 视频审核订单不派送
* @param paramMap
* @return
*/
public List<AutomaticAssignDto> automaticAssign(Map<String, Object> paramMap){
//派送规则
String changeSortSet = RedisCacheUtil.getValue(CACHE_TYPE.APP, "changeSortSet");
if (StringUtils.isBlank(changeSortSet)) {
changeSortSet = customerManager.getDictionaryByCode("changeSortSet");
if (StringUtils.isNotBlank(changeSortSet)) {
RedisCacheUtil.addValue(CACHE_TYPE.APP, "changeSortSet", changeSortSet,30,TimeUnit.DAYS);
} else {
changeSortSet = ConstantsUtil.AssignRule.FIFO; // 默认先进先审
}
}
AutomaticAssignDto automaticAssignDto = new AutomaticAssignDto();
automaticAssignDto.setChangeSortSet(changeSortSet);
automaticAssignDto.setUserTeam(CommonUtils.getValue(paramMap, "userTeam"));
List<AutomaticAssignDto> waitCheckList = automaticAssignMybatisDao.automaticAssignOrder(automaticAssignDto);
if(waitCheckList != null && waitCheckList.size()>0){
automaticAssignDto = waitCheckList.get(0);
automaticAssignDto.setSendStatus(ConstantsUtil.SendStatus.SEND);
automaticAssignDto.setBindTime(new Date());
automaticAssignDto.setUserId(Long.parseLong(paramMap.get("userId").toString()) );
int sum = automaticAssignMybatisDao.bindAutomaticAssignInfo(automaticAssignDto);
if(sum == 1){
     return waitCheckList;
}else{
//已被更新 则再次获取
return automaticAssign(paramMap);
}
}else{
return null;
}
}

学习自 https://blog.csdn.net/zhangdehua678/article/details/79594212

案例二

package what21.thread.lock;

public class OptimLockMain {

    // 文件版本号
static int version = 1;
// 操作文件
static String file = "d://IT小奋斗.txt"; /**
* 获取版本号
*
* @return
*/
public static int getVersion(){
return version;
} /**
* 更新版本号
*/
public static void updateVersion(){
version+=1;
} /**
* @param args
*/
public static void main(String[] args) {
for(int i=1;i<=5;i++){
new OptimThread(String.valueOf(i),getVersion(),file).start();
}
} } package what21.thread.lock; import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException; public class OptimThread extends Thread { // 文件版本号
public int version;
// 文件
public String file; public OptimThread(String name,int version,String file){
this.setName(name);
this.version = version;
this.file = file;
} public void run() {
// 1. 读取文件
String text = read(file);
println("线程"+ getName() + ",文件版本号为:" + OptimLockMain.getVersion());
println("线程"+ getName() + ",版本号为:" + getVersion());
// 2. 写入文件
if(OptimLockMain.getVersion() == getVersion()){
println("线程" + getName() + ",版本号为:" + version + ",正在执行");
// 文件操作,这里用synchronized就相当于文件锁
// 如果是数据库,相当于表锁或者行锁
synchronized(OptimThread.class){
if(OptimLockMain.getVersion() == this.version){
// 写入操作
write(file, text);
// 更新文件版本号
OptimLockMain.updateVersion();
return ;
}
}
}
// 3. 版本号不正确的线程,需要重新读取,重新执行
println("线程"+ getName() + ",文件版本号为:" + OptimLockMain.getVersion());
println("线程"+ getName() + ",版本号为:" + getVersion());
System.err.println("线程"+ getName() + ",需要重新执行。");
} /**
* @return
*/
private int getVersion(){
return this.version;
} /**
* 写入数据
*
* @param file
* @param text
*/
public static void write(String file,String text){
try {
FileWriter fw = new FileWriter(file,false);
fw.write(text + "\r\n");
fw.flush();
fw.close();
} catch (IOException e) {
e.printStackTrace();
}
} /**
* 读取数据
*
* @param file
* @return
*/
public static String read(String file){
StringBuilder sb = new StringBuilder();
try {
File rFile = new File(file);
if(!rFile.exists()){
rFile.createNewFile();
}
FileReader fr = new FileReader(rFile);
BufferedReader br = new BufferedReader(fr);
String r = null;
while((r=br.readLine())!=null){
sb.append(r).append("\r\n");
}
br.close();
fr.close();
} catch (IOException e) {
e.printStackTrace();
}
return sb.toString();
} /**
* @param content
*/
public static void println(String content){
System.out.println(content);
} }

学习自https://blog.csdn.net/qq897958555/article/details/79337064

最新文章

  1. 基于spring注解AOP的异常处理
  2. 设计模式之美:Template Method(模板方法)
  3. Thrift 个人实战--Thrift 网络服务模型
  4. Java正则表达式的最简单应用
  5. tmux使用
  6. json接口相关(建议结合JFinal框架)
  7. git打包
  8. 从零开始学习前端JAVASCRIPT — 14、闭包与继承
  9. 获取各种编码(Unicode,UTF8等)的识别符
  10. VIsual Studio编译OpenCV:无法打开python27_d.lib(python36_d.lib)的问题
  11. GBT MBR
  12. 由asp的一个错误,看语言的不同:asp &amp; java
  13. apache ftp server的简单入门(数据库验证)
  14. JS组件系列——JsPlumb制作流程图及相关效果详解
  15. 理解Scroller
  16. NodeList、HTMLCollection和NamedNodeMap
  17. lintcode-425-电话号码的字母组合
  18. Calendar Provider
  19. centos下防火墙iptables日志学习笔记
  20. C#中使用正则

热门文章

  1. 华为OJ平台试题 —— 数组:输入n个整数,输出当中最小的k个
  2. iOS项目开发实战——自己定义圆形进度提示控件
  3. VS2008让Release配置也能调试起来~
  4. PrintArea打印,@media screen解决移动web开发的多分辨率问题,@media print设置打印的样式
  5. 【转】Linux下mysql操作
  6. DotNet软件开发框架
  7. python 之 内置函数大全
  8. AtCoder Tak and Hotels
  9. URAL 2040 Palindromes and Super Abilities 2(回文树)
  10. java 如何将实体bean和map互转化 (利用Introspector内省)