简要说明:

表设计时,需要往表里加一个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

Java乐观锁的实现原理(案例)的更多相关文章

  1. JAVA乐观锁实现-CAS

    是什么 全称compare and swap,一个CPU原子指令,在硬件层面实现的机制,体现了乐观锁的思想. JVM用C语言封装了汇编调用.Java的基础库中有很多类就是基于JNI调用C接口实现了多线 ...

  2. Java乐观锁实现之CAS操作

    介绍CAS操作前,我们先简单看一下乐观锁 与 悲观锁这两个常见的锁概念. 悲观锁: 从Java多线程角度,存在着“可见性.原子性.有序性”三个问题,悲观锁就是假设在实际情况中存在着多线程对同一共享的竞 ...

  3. 深入分析 Java 乐观锁

    前言 激烈的锁竞争,会造成线程阻塞挂起,导致系统的上下文切换,增加系统的性能开销.那有没有不阻塞线程,且保证线程安全的机制呢?--乐观锁. 乐观锁是什么? 操作共享资源时,总是很乐观,认为自己可以成功 ...

  4. JAVA乐观锁、悲观锁实现

    一.名词解释 1.悲观锁:认为每次对数据库的操作(查询.修改)都是不安全的,因此每次操作都会把这条数据锁掉,直到本次操作完毕释放该锁 2.乐观锁:查询数据的时候总是认为是安全的,不会锁数据:等到更新数 ...

  5. Java乐观锁、悲观锁

    乐观锁 乐观锁(Optimistic Lock), 顾名思义,就是很乐观,每次去拿数据的时候都认为别人不会修改,所以不会上锁,但是在更新的时候会判断一下在此期间别人有没有去更新这个数据,可以使用版本号 ...

  6. java 乐观锁 vs 悲观锁

    在数据库的锁机制中介绍过,数据库管理系统(DBMS)中的并发控制的任务是确保在多个事务同时存取数据库中同一数据时不破坏事务的隔离性和统一性以及数据库的统一性. 悲观锁其实就是 完全同步 比如 sync ...

  7. java 乐观锁CAS

    乐观锁是一种思想,本身代码里并没有lock或synchronized关键字进行修饰.而是采用一种version. 即先从数据库中查询一条记录得到version值,在更新这条记录时在where条件中对这 ...

  8. Elasticsearch系列---并发控制及乐观锁实现原理

    概要 本篇主要介绍一下Elasticsearch的并发控制和乐观锁的实现原理,列举常见的电商场景,关系型数据库的并发控制.ES的并发控制实践. 并发场景 不论是关系型数据库的应用,还是使用Elasti ...

  9. Hibernate 悲观锁,乐观锁

    业务逻辑的实现过程中,往往需要保证数据访问的排他性.因此,我们就需要通过一些机制来保证这些数据在某个操作过程中不会被外界修改,这样的机制,在这里,也就是所谓的“锁”,即给我们选定的目标数据上锁,使其无 ...

随机推荐

  1. 如何给RecyclerView加上滚动条--现在就教你

    时隔许久,我又要更博了,含蓄的话不多说了,今天我们的主题是这个RecyclerView.至于为什么要加个scrollBar?因为我的业务需求是需要一个实现成这样的, 效果图:(可能看起来比较粗糙,但功 ...

  2. Could not load type ‘System.ServiceModel.Activation.HttpModule’ from&

    1. 部署网站到IIS7.5,Window 2008的时候出现这个错误   2. 错误信息 Server Error in ‘/’ Application. Could not load type ‘ ...

  3. [Django] 问题记录追踪表

    关注的网站: https://simpleisbetterthancomplex.com/ Linux部署 1. Ubuntu下vsftpd安装部署 2. Utuntu下Django+Apache+W ...

  4. 03 Java图形化界面设计——布局管理器之FlowLayout(流式布局)

    前文讲解了JFrame.JPanel,其中已经涉及到了空布局的使用.Java 虽然可以以像素为单位对组件进行精确的定位,但是其在不同的系统中将会有一定的显示差异,使得显示效果不尽相同,为此java提供 ...

  5. Java异常处理中,try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后?

    Java异常处理中,try {}里有一个return语句,那么紧跟在这个try后的finally {}里的code会不会被执行,什么时候被执行,在return前还是后? 解答:会执行,在return前 ...

  6. java 理解java的三大特性之继承

    继承定义了类如何相互关联,共享特性.对于若干个相同或者相识的类,我们可以抽象出他们共有的行为或者属相并将其定义成一个父类或者超类,然后用这些类继承该父类,他们不仅可以拥有父类的属性.方法还可以定义自己 ...

  7. oracle11g卸载,10g之类版本通用

    鉴于oracle一些比较稀奇的问题,本人没碰到的不能帮忙解决的.而且比较着急赶时间的亲们,我就只能推荐先卸载在安装的办法了,这个方法一般用时也就1个小时到1个半小时之间,切记按步骤删除,别漏删了,不然 ...

  8. java Thread方法解析: sleep join wait notify notifyAll

    转载自: sleep(),yield(),wait()区别详解:http://dylanxu.iteye.com/blog/1322066 join方法详解:http://www.open-open. ...

  9. Dynamics CRM 系统自己定义部分的语言翻译

    Dynamics CRM 自带语言切换功能,在官网下载所需语言包安装后,在设置语言中就能看到你所加入的语言.勾选要启用的语言应用就可以.再打开系统设置--语言就能看到可更改用户界面语言的显示了. wa ...

  10. 【SR】正则化超分辨率复原

    正则化超分辨率图像重建算法研究--中国科学技术大学 硕士学位论文--路庆春 最大后验概率(MAP)的含义就是在低分辨率图像序列已知的前提下,使高分辨率图像出现的概率达到最大.