本文版权归博客园和作者本人吴双共同所有 。转载爬虫请注明地址,博客园蜗牛 http://www.cnblogs.com/tdws/p/5712835.html

蜗牛Redis系列文章目录http://www.cnblogs.com/tdws/tag/NoSql/

Redis Clusterhttp://www.cnblogs.com/tdws/p/7710545.html

其实说多线程修改数据也不合适,毕竟redis服务端是单线程的,所有命令串行执行,只是在客户端并发发送命令的时候,导致串行的命令一些排列问题和网络时间差等造成数据不一致。本文虽然是数字的加减,但是为了说明锁的情况,故意不是用原子命令incr。也并非分布式锁的正确实现,没有考虑一些重入性等,稍后会整理一篇分布式锁的实践。

Redis分布式锁 http://www.cnblogs.com/tdws/p/5808528.html

ZK+curator 分布式锁 http://www.cnblogs.com/tdws/p/5874686.html

先配上一个简易的RedisHelper,一个set值,一个get值,一个设置并发锁,以便在我后面的操作中,你能清楚我究竟做了什么。

  public class RedisHelper
{
public RedisClient client = new RedisClient("127.0.0.1", );
public void Set<T>(string key, T val)
{
client.Set(key, val);
}
public T Get<T>(string key)
{
var result = client.Get<T>(key);
return result;
}
public IDisposable Acquire(string key)
{
return client.AcquireLock(key);
}
}

下面看一下并发代码,我只new了两个Thread。两个线程同时想访问同一个key,分别访问五万次,在并发条件下,我们很难保证数据的准确性,请比较输出结果。

 static void Main(string[] args)
{
RedisHelper rds = new RedisHelper();
rds.Set<int>("mykey1", );
Thread myThread1 = new Thread(AddVal);
Thread myThread2 = new Thread(AddVal);
myThread1.Start();
myThread2.Start();
Console.WriteLine("等待两个线程结束");
Console.ReadKey();
} public static void AddVal()
{
RedisHelper rds = new RedisHelper();
for (int i = ; i < ; i++)
{ int result = rds.Get<int>("mykey1");
rds.Set<int>("mykey1", result + ); }
Console.WriteLine("线程结束,输出" + rds.Get<int>("mykey1"));
}

是的,和我们单线程,跑两个50000,会输出100000。现在是两个并发线程同时跑在由于并发造成的数据结果往往不是我们想要的。那么如何解决这个问题呢,Redis已经为我们准备好了!

你可以看到我RedisHelper中有个方法是 public IDisposable Acquire(string key)。  也可以看到他返回的是IDisposable,证明我们需要手动释放资源。方法内部的 AcquireLock正是关键之处,它像redis中索取一把锁头,被锁住的资源,只能被单个线程访问,不会被两个线程同时get或者set,这两个线程一定是交替着进行的,当然这里的交替并不是指你一次我一次,也可能是你多次,我一次,下面看代码。

  static void Main(string[] args)
{
RedisHelper rds = new RedisHelper();
rds.Set<int>("mykey1", );
Thread myThread1 = new Thread(AddVal);
Thread myThread2 = new Thread(AddVal);
myThread1.Start();
myThread2.Start();
Console.WriteLine("等待两个线程结束");
Console.ReadKey();
} public static void AddVal()
{
RedisHelper rds = new RedisHelper();
for (int i = ; i < ; i++)
{
using (rds.Acquire("lock"))
{
int result = rds.Get<int>("mykey1");
rds.Set<int>("mykey1", result + );
}
}
Console.WriteLine("线程结束,输出" + rds.Get<int>("mykey1"));
}

可以看到我使用了using,调用我的Acquire方法获取锁。

输出结果最后是100000,正是我们要的正确结果。前面的8W+是因为两个线程之一先执行结束了。

还有,在正式使用的过程中,建议给我们的锁,使用后删除掉,并加上一个过期时间,使用expire。

以免程序执行期间意外退出,导致锁一直存在,今后可能无法更新或者获取此被锁住的数据。

你也可以尝试一下不设置expire,在程序刚开始执行时,关闭console,重新运行程序,并且在redis-cli的操作控制台,get你锁住的值,将会永远获取不到。

所有连接此redis实例的机器,同一时刻,只能有一个获取指定name的锁.

下面是StackExchange.Redis的写法

            var info = "name-"+Environment.MachineName;
//如果5秒不释放锁 自动释放。避免死锁
if (db.LockTake("name", info, TimeSpan.FromSeconds()))
{
try
{ }
catch (Exception ex)
{ }
finally
{ db.LockRelease("name", token);
}
}

Redis修改数据多线程并发—Redis并发锁的更多相关文章

  1. redis清除数据/xargs使用

    redis清除数据/xargs使用 redis比memcache好的地方之一,如果memcache,恐怕就得关掉重启了. 1 使用cli FLUSHDB 清除一个数据库,FLUSHALL清除整个red ...

  2. Redis Cluster数据分片机制

    复制粘贴自: https://www.e-learn.cn/content/redis/2344485, 点击链接访问原文 仅供个人学习参考之用, 如有侵权, 请联系删除! 高级开发不得不懂的Redi ...

  3. 更高效地提高redis client多线程操作的并发吞吐设计

    Redis是一个非常高效的基于内存的NOSQL数据库,它提供非常高效的数据读写效能.在实际应用中往往是带宽和CLIENT库读写损耗过高导致无法更好地发挥出Redis更出色的能力.下面结合一些redis ...

  4. 使用Redis中间件解决商品秒杀活动中出现的超卖问题(使用Java多线程模拟高并发环境)

    一.引入Jedis依赖 可以新建Spring或Maven工程,在pom文件中引入Jedis依赖: <dependency> <groupId>redis.clients< ...

  5. Redis结合Lua脚本实现高并发原子性操作

    从 2.6版本 起, Redis 开始支持 Lua 脚本 让开发者自己扩展 Redis … 案例-实现访问频率限制: 实现访问者 $ip 在一定的时间 $time 内只能访问 $limit 次. 非脚 ...

  6. Java多线程与并发模型之锁

    这是一篇总结Java多线程开发的长文.文章是从Java创建之初就存在的synchronized关键字引入,对Java多线程和并发模型进行了探讨.希望通过此篇内容的解读能帮助Java开发者更好的理清Ja ...

  7. Redis常用数据类型和事物以及并发

    Redis数据类型 基本类型(String int): 如 set key value .get key 等 所有命令都是按照 key value keys * 可以将全部数据列出,其中后面的 &qu ...

  8. 高并发Redis(Mac)环境配置(一)

    一.产生原因: SNS交互型网站的兴起,对于高并发,大负载数据的操作,海量数据的存储和访问 NoSql四种类型: 键值存储(Redis优点可以快速查询,缺点缺少存储的结构化)              ...

  9. 为什么 redis 单线程却能支撑高并发

    redis 和 memcached 有什么区别?redis 的线程模型是什么?为什么 redis 单线程却能支撑高并发? 这个是问 redis 的时候,最基本的问题吧,redis 最基本的一个内部原理 ...

随机推荐

  1. HTML5- Canvas入门(六)

    已经第六章了,也差不多接近尾声,如果你从第一章耐心follow到本章结束,那你便能掌握canvas的大部分知识点(当然如果要精通,还是得多靠练习,做一些小案例). 今天我们要学习的是canvas的变形 ...

  2. 【腾讯Bugly干货分享】WebP原理和Android支持现状介绍

    本文来自于腾讯bugly开发者社区,未经作者同意,请勿转载,原文地址:http://dev.qq.com/topic/582939577ef9c5b708556b0d 1.背景 目前网络中图片仍然是占 ...

  3. windows下Meteor+AngularJS开发的坑

    有复杂的地方我再开贴记录,这里只记录容易解决的坑. 1. windows下手工增加smart package.直接将下载下来的包扔到meteor package中.记得将文件夹名字改得和smart.j ...

  4. The Hacker's Guide To Python 单元测试

    The Hacker's Guide To Python 单元测试 基本方式 python中提供了非常简单的单元测试方式,利用nose包中的nosetests命令可以实现简单的批量测试. 安装nose ...

  5. ubuntu升级内核后vmware-player启动失败

    在虚拟机软件中,vmware player是对硬件支持很好的,通过它可以很方便的使用网银.单片机开发等等工作.但是最近ubuntu每次升级内核后,vmware都会启动失败,提示:Before you ...

  6. 《Entity Framework 6 Recipes》中文翻译系列 (13) -----第三章 查询之使用Entity SQL

    翻译的初衷以及为什么选择<Entity Framework 6 Recipes>来学习,请看本系列开篇 3-4使用实体SQL查询模型 问题 你想通过执行Entity SQL语句来查询你的实 ...

  7. 学习RBAC 用户·角色·权限·表

  8. layout

    <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title> ...

  9. FASTJSON

    package com.hanqi.test; import java.util.ArrayList;import java.util.Date;import java.util.List; impo ...

  10. Chrome开发者工具不完全指南(四、性能进阶篇)

    前言 Profiles面板功能的作用主要是监控网页中各种方法执行时间和内存的变化,简单来说它就是Timeline的数字化版本.它的功能选项卡不是很多(只有三个),操作起来比较前面的几块功能版本来说简单 ...