原则上,乐观锁可以用数据库去做,这里我用了Redis做乐观锁。
如果不懂什么是乐观锁,可以百度下,很多高手写得很详尽。
public static void main(String[] args) {
RedissonClient redisson = null;
try{
Config config = new Config();
config.useSingleServer().setAddress("127.0.0.1:6379");
redisson = Redisson.create(config);
RAtomicLong rAtomicLong = redisson.getAtomicLong("optiLock");
rAtomicLong.set(1);
Thread t = new Thread(()->{
try{
RedissonClient redisson1 = Redisson.create(config);
RAtomicLong rAtomicLong1 = redisson1.getAtomicLong("optiLock");
Long nowVersion = rAtomicLong1.get() ;
System.out.println("Thead1得到版本号"+nowVersion);
//得到乐观锁的值,操作其它功能。。。
Thread.sleep(10000);
RLock rLock = redisson1.getLock("myLock");
//操作乐观锁值,需要加个锁,避免并发冲突
System.out.println("Thead1操作完成,去查看乐观锁值");
rLock.lock();
rAtomicLong1 = redisson1.getAtomicLong("optiLock");
Long nowVersion2 = rAtomicLong1.get() ;
if(nowVersion.equals(nowVersion2)){
rAtomicLong1.set(nowVersion2+1);
System.out.println("Thead1修改了版本号"+nowVersion2);
}else {
System.out.println("版本号失败,操作回滚,新版本号:"+nowVersion2);
}
rLock.unlock();
//可以提交操作了
System.out.println("Thead1结束");
redisson1.shutdown();
}
catch (Exception ex){}
});
t.start();
Thread t2 = new Thread(()->{
RedissonClient redisson1 = Redisson.create(config);
RAtomicLong rAtomicLong1 = redisson1.getAtomicLong("optiLock");
Long nowVersion = rAtomicLong1.get();
System.out.println("Thead2得到版本号"+nowVersion);
//得到乐观锁的值,操作其它功能。。。
RLock rLock = redisson1.getLock("myLock");
//操作乐观锁值,需要加个锁,避免并发冲突
System.out.println("Thead2操作完成,去查看乐观锁值");
rLock.lock();
rAtomicLong1 = redisson1.getAtomicLong("optiLock");
Long nowVersion2 = rAtomicLong1.get() ;
if(nowVersion.equals(nowVersion2)){
rAtomicLong1.set(nowVersion2+1);
System.out.println("Thead2修改了版本号"+nowVersion2);
}else {
System.out.println("版本号失败,操作回滚,新版本号:"+nowVersion2);
}
rLock.unlock();
//可以提交操作了
System.out.println("Thead2结束");
redisson1.shutdown();
});
t2.start();
}
catch (Exception ex){
System.out.println(ex.getMessage());
}
finally {
redisson.shutdown();
}
}
运行结果:

运行时,Thread1和Thead2同时得到了乐观锁的版本号1,而Thread1的运行时间比较久的关系,Thread2已经运行完毕,并且修改了版本号为2 。等到Thread1运行完,发现版本号已经被修改了,与自己原先取得的版本号不同,于是只能回滚操作。
注意在操作完后,查看当前版本号前必须加锁(悲观锁),否则可能会出现冲突。
这种方式适合于冲突不多的场景,如果冲突很多,数据争用激烈,会导致不断地尝试,反而降低了性能。
网友评论