首页 文章 精选 留言 我的

精选列表

搜索[趋势探讨],共10000篇文章
优秀的个人博客,低调大师

物联网时代 农业搭上现代化快车成趋势

近年来,我国农业现代化取得巨大成就,正逐步摆脱“靠天吃饭”的老印象。但科技发展日新月异,在美国亚利桑那州的田间,无人驾驶拖拉机穿梭其中,大批“生菜机器人”在查看每株作物的生长情况,农场主只需通过手机便可掌控农场的核心数据……与此相比,我国农业发展的潜力依然巨大。从土壤分析到作物种植,从天气监测到施肥撒药等,由大数据和人工智能驱动的智慧农业(000816,股吧),正在逐步改变着我国现有的农业生产方式,智慧农业正催生出一个巨大的市场。回看2015年,被提及最多的词语莫过于大数据、云计算。这些高精尖技术已被各个领域所熟知并运用。 而与这两个词联系最为密切的另一个词是——物联网技术。 农业作为一个特殊的产业,其生产存在季节性、地域性强,生产者分散且生产周期长,生产出来的产品标准化程度低等,是长期困扰发展的主要问题。农业要走出困境,摆脱其固有问题,建立强有力的信息服务,高效生产管理以及发展农产品(000061,股吧)流通新模式刻不容缓。 在传统农业中人们获取农田信息的方式都很有限,主要是通过人工测量,获取过程需要消耗大量的人力,而物联网通过使用无线传感器网络可以有效降低人力消耗和对农田环境的影响,获取精确的作物环境和作物信息。 我们从农产品生产不同的阶段来看,无论是从种植的培育阶段和收获阶段,都可以用物联网的技术来提高它工作的效率和精细管理。 人工调整作业环境、影响作物生长、高投入、高产出的设施农业进行小区域信息监测; 根据不同作物不同生长条件,更有针对性的设置不同监测指标,个性化的信息服务; 农技专家针对不同用户、不同小区域监测到的告警信息,给予专业的指导性建议和合理化改进措施。 高水平技术平民化,使用方便,操作简单。设施农业物联网的应用可以帮助农民减少因信息不灵、措施不力等因素引起的损失,保障农民收入,丰富城市菜篮子,促进社会发展,是一项利国利民的事情。 设施农业物联网系统,让农民买得起,用得起。移动通信设备与互联网有机结合进行的生产管理活动,不受时间和地点的限制,能够真正实现随时随地的生产监管,而且移动终端的身份固定,能够向用户提供个性化移动交易服务,并可以提供与位置相关的交易服务。另外,以手机为代表的移动终端在农村的广泛普及也为农业移动电子商务的发展提供了现实可能性。 利用物联网技术,切实解决了信息化在农业生产、经营活动中的深度应用。农业物联网系统的广泛应用,也必将让农民看到运用先进技术带来的效益。 农业部发布的《全国农业可持续发展规划(2015-2030)》中提到,到2020年,农业科技进步贡献率达到60%以上,主要农作物耕种收综合机械化水平达到68%以上。而这些都需要物联网技术的支持。 物联网技术在我省农牧业生产领域中应用已经起步,面临着困难和挑战的同时,也面临着机遇。我们要从物联网技术等新型信息技术适用型人才培养着手,加大投资比例,加快发展步伐。 以信息化提升农业生产,构建新型农产品营销网络,构筑农产品质量安全监管体系,提高科技入户水平,那么,实现农业技术、市场信息的“零距离”服务,解决农业技术推广工作“最后一公里”难题将不再是问题。 现代农业插上了信息化的翅膀,就能飞得更高、更远。 本文转自d1net(转载)

优秀的个人博客,低调大师

物联网趋势下 系统集成商愈发重要

物联网是各终端、各种软件整合互联互动的最终产物,随着国家不断深化智慧城市的推广建设,完善物联网应用的配套设施和技术,物联网背后的市场产值大得不可估量。目前,物联网里单独应用的产品已逐渐减少,越来越多的是通过系统集成,建立产品与软件的大范围应用。 为什么需要系统集成商 所谓的系统集成,按照美国信息技术协会的定义,就是根据一个复杂的信息系统或子系统的要求,把多种产品和技术验明并接入一个完整的解决方案的过程。目前主流的系统集成做法,有设备系统集成和应用系统集成两大类。 面对物联网复杂应用环境和众多不同领域的设备,传统的项目建设模式——由投资方独自去对接设计院、设备厂家、电力公司等,无论在效率和质量都无法跟上现时的需求。相对于传统模式,系统集成商的优点有: 1、工程项目责任的单一性; 2、最大化地实现了最终用户的投资价值; 3、解决各类设备、子系统间的接口、协议、系统平台、应用软件等与子系统、建筑环境、施工配合、组织管理和人员配备相关的问题; 4、保证客户得到最合适的解决方案; 总体来说,系统集成商能较好的解决了工程设备工艺规范不统一问题、兼容性问题、对项目管理、设计、监管等有整体的把控。 系统集成市场发展迅猛 据了解,国内系统集成市场规模保持较高速度的增长,行业规模的增长一直保持在16-23%之间,随着国家政策的支持,加之云计算、移动互联网等新技术驱动,物联网未来发展中,系统集成的需求将大量增长,势必成为发展势头最猛的一个产业。 本文转自d1net(转载)

优秀的个人博客,低调大师

移动互联网趋势:平板消亡、APP当道、情境计算

无 论是国外Instagram和Whatsapp的天价奇迹还是国内BAT三大巨头无节操的收购,移动互联网带来的巨大红利让全球的资本和注意力都聚集到一 个环节上——Mobile。前两天在北京举行的移动互联网大会上,简直就是年轻人的海洋,如果说互联网公司是年轻人的公司,那么移动互联网公司则可能是更 年轻人的集合体,因为年轻,所以更有激情。但尽管踏上移动互联网这个“上行”电梯,但如果方向不对,依然无法到达终点,下面来看看移动互联网未来的三个趋 势。 平板渐趋消亡 几年前人们一度认为上网本会替代传统笔记本,但这个念想被iPad无情 的毁灭了,也差点让主打上网本的宏碁和华硕倒闭。随着iPad的流行,好事者再度认为iPad还会消灭传统笔记本,但当iPad发布后的第四年,从苹果最 新一季的财报里看,iPad的销量开始下滑,只卖出1640万台,较去年同期2000万台的销量有明显下滑。 而如果细心去观察iPad的销 量变化图,如下图所示,会明显看到,与iPhone相比,iPad的增速已明显放缓,甚至可以说几乎停滞。分析人士认为,平板电脑与手机不同,其更新换代 的频率很低。而来自皮尤的调查则揭示了另外一个有趣的数字:在15到55的年龄段中,拥有平板电脑最多的是30—55岁的人,而最少的则是15—20岁。 皮 尤认为,年长者喜欢使用平板电脑的原因在于他们认为平板可以成为传统笔记本的部分替代品,大屏对习惯使用浏览器的年长者非常有吸引力。而年轻人没有使用浏 览器上网的习惯,他们早已对APP接入互联网的模式习以为常,也因此,他们对平板电脑的需求很小。如一位小朋友所言:平板电脑更像是个游戏机还不是上网设 备。 当手机尺寸越来越大,也让手机和平板的界限日益模糊。而以手机为主要设备的年轻人群体正在成为社会中坚力量,所有这些因素都让平板电脑的未来变得岌岌可危,平板电脑也曾一度让很多传统媒体觉得找到了大救星,但目前来看,这些传统媒体需要继续寻找”新救星“了。 独立的APP更受青睐 如 上文所言,用户在平板电脑和智能手机上的使用习惯是不一样的,及时是同一款系统,比如iPad和iPhone都是运行的移动设备,但用户在iPad上使用 浏览器的频率更高,而iPhone用户则更钟爱各式各样的APP,他们早已习惯用这些APP访问互联网,从吃喝玩乐到办公生活。 传统互联网 时代,除了一些基本的工具软件之外,用户的所谓上网几乎都是围绕web浏览器展开的,书签栏里的书签就是一个个服务入口。如今,在移动互联网时代,独立的 APP成为新的触点。与桌面浏览器大而全的功能不同,移动APP越来越多的追求小而美的效果。其中基本的原则——一个APP解决一个问题。 这 当然和国内移动APP的现状有些差异,原因也不难理解,如今国内移动互联网市场还是传统互联网公司所把持,比如BAT。很多传统互联网软件(应用)的习惯 延续到了移动互联网上,导致移动APP臃肿不堪,这在Android平台尤其严重,那些出自国内顶尖互联网公司的应用运行起来卡顿明显。除Android 系统碎片化和不同硬件平台的因素外,APP集成了太多服务是主要原因。 而国外一些应用,比如Snapchat、Instgarm、 Secret则真正贯彻了小而美的理念。或许这些为移动而生的服务无法代表业界的整个潮流,那不妨看看以传统互联网起家的Facebook和 Google,Facebook日前将messenger作为一个单独的APP推向市场,下一步还会让paper独立运行。而Google则把文档和表格 应用从Google Drive里移出,成为两个独立应用。 受限于手机软硬件的不足,用户对移动APP的体验非常关注,通过这些独立的 APP,开发者能让用户更好的解决某一个方面的需求,提升体验效果。并且,大量移动APP组成的品牌矩阵也能增强用户的使用粘性。或许将来的某一天,你在 手机上打开命名为”Google“的文件夹,里面放置了所有Gmail、音乐、文档、表格等多个单独应用,就像当年打开打开浏览器的书签一样。 情境计算 我曾经不止一次的说起搜索的未来是人工智能,当然这来自Google创始人佩奇的观点。移动互联时代,搜索的重要性不言而喻,而且极有可能造就第二个Google。但移动互联网的搜索绝非简单的能找到资料,而是基于情境计算的推荐。 移 动互联网带给世界最大的改变是数据生产变得简单,尤其是图片、声音、位置三大方面的数据,再加上可穿戴设备上的各种传感器数据,都成为目前移动互联网企业 最激烈的战场。情境计算则是通过整合来自移动设备上不同数据,将个人的生活、工作都变成可追踪的比特流,然后根据特定的情境向用户push特定的信息。 雅 虎美女总裁梅耶这样描述情境计算:”情境计算基于用户所处的位置、所做的事情,在正确的时间和地点推送给用户正确的信息。“ 梅耶也表示,只有移动设备才能更好的收集用户的这些位置与行为信息。梅耶对情境计算的关注也反映在一些硅谷公司的收购:Twitter买下Android 桌面产品Cover;Yahoo则买了Cover的竞争对手Aviate;苹果收购智能助手Cue。除此之外,搜索巨人Google在不断打磨的 Google Now也是基于用户情境来推送消息。 Google now背靠Google庞大的搜索数据,并利用强大的算法对数据进行分析挖掘,并结合地点和时间推送做相应的推送。由于众所周知的原因,国内用户还无法完 美体验到Google Now。但即使在国外,Google Now目前还很笨,最明显的问题就是无法让时空和信息进行良好的匹配,譬如国外很多用户反应,他们的Google Now常常会在上班时间发来一条通知:告诉你从办公室回家的路线以及交通拥堵情况,但事实上,你此时并不需要这类信息。从这个角度来看,即使如 Google这样的巨鳄,短期内也还无法提供优质的情境计算服务,未来还需要继续努力。 大约四年前,时任连线杂志主编的克里斯安德森高 呼:web已死,Internet永生!当时引起很多人的非议,如今来看这句话,却有着极大的前瞻性。随着PC业的没落、传统PC和互联网企业纷纷转型, 由iPhone引发的APP潮流让人类踏入移动互联的新时代。当越来越多的用户依靠APP而非浏览器访问互联网时,web已无足轻重。如今,人类处在”无 处不连接“与”无时不连接“的时代,海量移动数据为情境计算提供了良好基础,也吹响了走向人工智能的号角。 文章转载自 开源中国社区[http://www.oschina.net]

优秀的个人博客,低调大师

架构师之路(十二)之探讨一下高并发场景下分布式锁该用哪种方式实现较好?

什么是分布式锁? 分布式锁是控制分布式系统之间同步访问共享资源的一种方式。 在 分布式系统中,常常需要协调他们的动作。如果不同的系统或是同一个系统的不同主机之间共享了一个或一组资源,那么访问这些资源的时候,往往需要互斥来防止彼此干扰来保证 一致性,这个时候,便需要使用到分布式锁。 各位兄弟姐妹们,上述介绍来自度娘,直接搬过来看的概念,如果还不明白,下面直接来张图,跟大家简单说一下分布式锁到底是干啥的. 图 1-1 我简单的画了一幅图,解释一下图: 1) 三个用户,代表了三个不同请求,也就是三个不同的进程 2) 三个主机,代表了分布式架构中多主机部署的情况 3) 一个系统,代表了部署在主机上的应用 4) 一个资源,代表了多用户访问相同资源的情况 5) 增加了一把锁,而这个锁就是今天要说的分布式锁,它是由系统来控制,不同进程访问需要加锁控制,已求达到互斥访问,资源原子性的目的 这就是分布式锁,这下应该明白了啥是分布式锁了吧,,,各位亲...那么我们为啥要用分布式锁,请听我接下来继续唠.. 为啥用分布式锁? 其实在上一章节,这个问题就已经回答过了,通过上图的描述,除了介绍什么是分布式锁以外,其实隐含着回答了,我们为什么要用分布式锁,显而易见嘛,如果你不用分布式锁,大家都去争抢同一个资源,一定会造成资源的重复访问,重复操作,那么对业务而言将会产生很可怕的后果! 失去锁,有何危害? 各位读者,应该很庆幸能读到本片文章吧,嘻嘻,,大家试想一下,你们的公司业务有那么一个场景: 1) 你们的系统部署在不同的主机或虚拟机上,并且实现了分布式部署, 2)某一时刻,用户正在做业务,并且是处在高并发场景下,假设当前的多个相同业务请求落到了四台tomcat应用服务器上,那么就至少有四个进程 要开始工作; 3)这四个进程需要操作同一份订单数据,但很可惜的是,你们的业务系统并没有锁处理机制,导致了同一时刻,同一份订单数据在同一时间内被反复 操作,修改甚至删除,并且每次请求之后,都会将结果响应给终端用户,那么这个时候除了造成业务数据恐怖的不一致以外,很有可能会造成数据库的假死,锁表等的现象,这在高并发业务场景中将会很可怕! 分布式有何讲究? 我相信,当前较为流行的应用部署一定是基于分布式结构,分布式思想提出也有N年的时间了,现在大家只要一说到系统部署应该首先想到的就是分布式的结构,没错,传统的集中式有太多的局限性了,我们这里不再说二者区别,相信大家比我都明白吧,,呵呵, 在分布式世界中,有一个CAP的理论,C代表的一致性(Consistency),A代表的是高可应用行(Available),P代表的是高容错性(Partition tolerance), 是说一个再牛逼哄哄的分布式系统,CAP也才能有其二同时满足,这也说明了鱼和熊掌不可兼得。在绝大多数的高并发业务场景中,要么牺牲数据的一致性来达到服务的高可用;要么牺牲服务的高可用,来达到数据的一致性、实时性、准确性!所以,构造一个完美的业务系统架构,其实还是挺难的。 那么分布式系统只要遵循CAP原理,根据具体的业务要求,基本上都是可以实现的,那么分布式锁又需要具备哪些特点呢? 分布式锁具备的特点 大家不妨想一想,假设我们有个订单业务系统,需要定时处理订单的数据汇总业务,为防止同一个单子在同一时间被汇总多次,因此,我们需要加把锁,这把锁至少能隔离开不同的进程请求,或者说等当前的进程请求处理完毕,下一个进程才能接着处理下一个业务单子,操作同一份数据,那么至少得具备: 1)该锁必须的是排他性的 2)该锁必须是可重入的,如果有出现方法递归调用的时候,当前线程在最外层一旦获取了锁,那么该线程是可以继续使用这把锁访问被调用者的临界资源, 这个地方说起来有点绕口哈,简单说来就是,A方法调用B方法,并且A获取了锁,这个时候如果B是原子操作的,那么A方法在释放锁之前,B方法同时也会获得该锁的资源。这么解释应该明白了哈。所以这个把锁必须是可以重入的,否则起不到临界资源隔离的作用。 3)该锁必须得设置失效时间,否则会出现死锁等待的情况 4)该锁必须得具备高可用性 5)该锁必须具备高性能,因为频繁的获取锁、解锁会消耗cpu,以及内存 6)该锁必须具备异步非阻塞的能力,也就是线程申请失败,要及时返回获取锁失败 如何用分布式锁? 分布式锁的实现,在业内较为流行的做法有三种: 1)基于Mysql数据库的分布式锁 2)基于Redis的分布式锁 3)基于Zookeeper的分布式锁 接下来,用干货来介绍这三种分布式锁的优缺点, 基于Mysql数据库的分布式锁 基于数据库的分布式锁原理其实很简单,我们可以利用主键的唯一性,来记录当前线程的操作,那么主键应该记录的是临界资源的值,并且该值是唯一的。数据表中,主要还存在该值,或者状态是某个值,我们就认为,该方法或资源已经被加锁了。 案例说明 废话少说吧,直接贴上代码: /** * @Author: yuenbin * @Date :2020/9/14 * @Time :9:32 * @Motto: It is better to be clear than to be clever ! * @Destrib: 演示一下使用mysql的乐观锁,实现分布式锁 * 给线程加锁 **/ public void tryLock (String lockId,String ip ,String name ,int expire ){ DistLock distLock = new DistLock() ; distLock.setLockId(lockId); distLock.setHolderIp(ip); distLock.setHolderName(name); distLock.setExpire(expire); distLock.setStatus("1"); int affect = distLockService.insertSelective(distLock) ; if(affect > 0 ) { log.debug(lockId+"被线程"+name+"持有,请稍等...!"); } } @Scheduled(fixedRate = 1000) public void doTryMysqlLock(){ log.debug("定时器执行了..."); InetAddress inetAddress = null ; try { inetAddress = InetAddress.getLocalHost(); }catch (UnknownHostException ex ){ ex.printStackTrace(); } String clientIp = inetAddress.getHostAddress() ; //尝试获取分布式锁 boolean lock = tryLock("testDistLock", clientIp, Thread.currentThread().getName(), 2); if(lock){ log.debug("分布式锁获得成功..."); testDistLock(); unlock("testDistLock"); log.debug("释放分布式锁成功..."); }else { log.debug("分布式锁获得失败..."); DistLockExample distLockExample = new DistLockExample() ; distLockExample.createCriteria().andLockIdEqualTo("testDistLock") .andStatusEqualTo("1"); DistLock distLock = distLockService.selectFirstByExample(distLockExample); log.debug("分布式锁被{}占有,ip地址为:{}",distLock.getHolderName(),distLock.getHolderIp()); return; } } 解释一下: 1) 我创建了一张表,表名叫dist_lock,表结构如下: create table dist_lock ( id int not null auto_increment primary key, lock_id varchar(250) not null, expire int null, holder_name varchar(250) not null, holder_ip varchar(100) null, create_time datetime default CURRENT_TIMESTAMP null, update_time datetime default CURRENT_TIMESTAMP null, status char(4) null ) ; comment on column dist_lock.lock_id is '分布式锁主键' ; comment on column dist_lock.expire is '分布式锁过期时间' ; comment on column dist_lock.holder_name is '分布式锁持有者' ; comment on column dist_lock.holder_ip is '客户端ip地址' ; 2) 表中的lock_id表示临界资源值,status为1表示该资源被线程占有,也就是加了分布式锁, 3) 表中的expire表示该锁资源的失效日期,锁不可能无限期占有,必须加一个过期时间加以控制 我们来接着看一下这个过期时间是如何控制的,上干货: /** * @Author: yuenbin * @Date :2020/9/14 * @Time :10:36 * @Motto: It is better to be clear than to be clever ! * @Destrib: 每隔15秒扫一次过期锁 **/ @Scheduled(fixedRate = 1000*5 ) public void checkLock(){ log.debug("分布式锁过期时间检查开始...."); try { DistLockExample distLockExample = new DistLockExample() ; distLockExample.createCriteria().andStatusEqualTo("1"); List<DistLock> lockList = distLockService.selectByExample(distLockExample) ; if( null != lockList && lockList.size() > 0 ){ List<DistLock> filterList = lockList.stream().filter(distLock -> ifExpired(distLock.getLockId()) ).collect(Collectors.toList()); filterList.forEach(distLock -> { unlock(distLock.getLockId()); }); log.debug("过期的锁一共有:{"+filterList.size()+"}条"); } }catch (Exception ex ){ ex.printStackTrace(); } } /** * @Author: yuenbin * @Date :2020/9/14 * @Time :10:17 * @Motto: It is better to be clear than to be clever ! * @Destrib: 当前分布式锁是否过期 **/ public boolean ifExpired(String lockId){ boolean ifExpired = false ; DistLockExample distLockExample = new DistLockExample() ; distLockExample.createCriteria().andLockIdEqualTo(lockId) .andStatusEqualTo("1") ; DistLock distLock = null;//distLockService.selectFirstByExample(distLockExample) ; int expire = distLock.getExpire() ; long current = System.currentTimeMillis() ; //获取当前时间 long diff = expire * 1000 ; //预计过期时间 单位毫秒 Date date = distLock.getCreateTime() ; long expect = date.getTime() + diff ; if(current > expect ){ System.out.println(lockId+"已经过期了,准备解锁..."); ifExpired = true ; } return ifExpired ; } 解释一下: 1)checkLock的目的是定时检测一下数据库中的lock资源是否在规定时间内过期,在正常的业务场景中,必须有这么一个机制,否则可能会出现死锁的情况 2)如果有过期的情况出现,就要将该锁更新为失效,并为其他线程分配锁 那么解锁的过程如何呢,接着上干货: /** * @Author: yuenbin * @Date :2020/9/14 * @Time :10:10 * @Motto: It is better to be clear than to be clever ! * @Destrib: 解锁操作 **/ public void unlock(String lockId ){ DistLock distLock = new DistLock(); distLock.setStatus("0"); DistLockExample distLockExample = new DistLockExample() ; distLockExample.createCriteria().andLockIdEqualTo(lockId) .andStatusEqualTo("1") ; int affect = distLockService.updateByExampleSelective(distLock, distLockExample); if(affect >0 ){ log.debug(lockId+"解锁成功!"); } } 解锁操作其实很简单,只要满足特定的条件,把数据表中状态改掉即可。 mysql的分布式锁执行我是使用的springMVC搭建的框架,用单元测试实现的,后续大家可根据自己的喜好,搭建实现方式,下面,给大家贴一下执行效果吧,干货上起: 效果演示 //to-do 准备贴一下执行效果 执行效果 线程抢占情况 基于Redis的分布式锁 Redis实现分布式锁的原理其实也不复杂,其核心思想是使用redis自带的setnx()并配合getset()来实现分布式锁。下面用一张图介绍一下redis分布式锁的实现原理: 解释一下获取锁过程: 1)某一时刻,有多个线程想要从redis获取分布式锁,操作redis,并调用setnx命令 2)如果调用setnx命令,返回1表示,成功设置key,获取锁成功,如果返回0,表示该key已存在,并被其他线程给设置过。这里需要注意的是,为避免 出现死锁的可能,比如redis突然挂掉,或网络断开,那么其他进程在尝试获取锁的时候,没有设置过期时间,上一个进程将会一直持续持有锁,就会造成 死锁的发生,因此,在调用setnx命令的时候,需要将过期时间作为值赋给key。 3)接着调用get命令,获取该key,需要判断一下该key是否过期,如果过期了,需要调用getset()命令,将新的锁过期时间设置一下,设置成功将自动获取到该分布式锁,getset()命令操作是原子性的。 4)如果还未过期,则需要等待; 释放锁过程: 1)释放锁的时候,需要提前判断一下该锁是否过期,来保证多线程场景下的安全性,设想一下某一个线程拿到分布式锁之后,某一时刻该锁过期了,并且任务也执行完了,如果直接删除该锁,可能会把其他线程获取的锁也一并删除,这样直接操作会很危险 命令介绍 SETNX SETNX key value 将 key 的值设为 value,当且仅当 key 不存在。 若给定的 key 已经存在,则 SETNX 不做任何动作。 SETNX 是SET if Not eXists的简写。 返回值 返回整数,具体为 - 1,当 key 的值被设置 - 0,当 key 的值没被设置 案例说明 废话少说,直接上干货: redis 上锁过程 /** * @Author: yuenbin * @Date :2020/9/15 * @Time :15:38 * @Motto: It is better to be clear than to be clever ! * @Destrib: 加锁操作 redis **/ public boolean tryRedisLock(String key ,int expire ){ long value = System.currentTimeMillis() + expire*1000 ; boolean flag = RedisUtil.setnx(key , String.valueOf(value)); log.debug("当前获取锁状态{}",flag); if(flag){ return true ; } String oldExpired = RedisUtil.get(key) ; if(StringUtils.isNotBlank(oldExpired)){ boolean ifExceed = Long.parseLong(oldExpired) < System.currentTimeMillis() ; log.debug("是否超时{}?",ifExceed); //如果超时了,,则进行设置 if( ifExceed){ log.debug("redis--分布式锁超时,重新设置..."); String currentExpired = RedisUtil.getAndSet(key,System.currentTimeMillis()+expire*1000+"" ); if(currentExpired.equalsIgnoreCase(oldExpired)){ return true ; } } } return false ; } redis 释放锁过程 /** * @Author: yuenbin * @Date :2020/9/15 * @Time :15:37 * @Motto: It is better to be clear than to be clever ! * @Destrib: 解锁操作,,redis **/ public void unRedisLock(String key ){ String expired = RedisUtil.get(key) ; if(StringUtils.isNotBlank(expired)){ //未超时,则释放该锁 if(Long.parseLong(expired) > System.currentTimeMillis()){ RedisUtil.del(key); log.debug("redis--解锁成功 !"); } } } 效果演示 基于Zookeeper的分布式锁 zk实现的分布式锁既是一种公平锁,也是一种可重入锁。zk是当今互联网分布式架构体系中用的非常广泛的一种分布式协调器,非常多的互联网大厂都在 使用zk来管理协调组件,管理服务等。为什么说zk是一种公平锁呢?因为zk的节点可以控制有序性,我们可以规定节点编号排在最前面的,优先有执行权,这不就是锁的实现么?因此,zk可以构造一种阻塞或非阻塞的分布式公平锁,下面一张图介绍一下,zk实现的锁原理机制: 解释一下 1)zk实现分布式锁主要借助于zk特有的一种节点监听机制,这种节点监听机制有点类似于击鼓传花玩法,也就是从一个节点到下一个节点,不会出现跨节点传递通知的情况。这种机制的非常好的一点就是,避免了羊群效应,某一个节点挂掉,不会引起其他节点的批量监听,并批量做出应急反应,这样直接避免了服务器某时刻可能的巨大压力。 2)zk节点创建的时候,是有序的,有序的节点能保证获取锁的公平性。每个节点只需要关注或监听它的前一个节点,并保证自己当前的节点是所有节点中最小号,因为只有排在最前面,才有资格获取到锁。 3)zk创建的节点是临时节点,临时节点不会长久存在于zk,这样避免了zk挂掉或者出现网络问题的时候,不会出现死锁的情况。 案例说明 zk实现分布式锁的过程,这里有个实例,废话少说,直接上干货: /** * @Author: yuenbin * @Date :2020/9/16 * @Time :16:44 * @Motto: It is better to be clear than to be clever ! * @Destrib: 给节点上锁 **/ public boolean tryLock(String lockName ){ String currentNode=""; try { if(currentNode == null || currentNode.equals("")){ currentNode = zkClient.createEphemeralSequential(rootNode+"/", "lock"); currentNodeLocal.set(currentNode); System.out.println("["+currentNode+"]节点创建成功"); } List<String> children = zkClient.getChildren(rootNode); //升序排序 Collections.sort(children); if(currentNodeLocal.get().equalsIgnoreCase(rootNode +"/"+children.get(0))){ return true ; }else { // 寻找比tempNode小的节点,也就是排好序的当前节点的上一个位置节点 String beforeNode = children.get(Collections.binarySearch(children, currentNode.substring(currentNode.lastIndexOf("/")+1))-1); beforeNode=rootNode + "/"+beforeNode ; beforeNodeLocal.set(beforeNode); } } catch (Exception e) { } return false; } 等待获取锁: public void waitForLock() { countDownLatch = new CountDownLatch(1); System.out.println("节点["+currentNodeLocal.get()+"]正在等待["+beforeNodeLocal.get()+"]"); IZkDataListener iZkDataListener = new IZkDataListener() { @Override public void handleDataChange(String s, Object o) throws Exception { } @Override public void handleDataDeleted(String s) throws Exception { if(countDownLatch !=null){ countDownLatch.countDown(); } } } ; zkClient.subscribeDataChanges(beforeNodeLocal.get(), iZkDataListener); if (zkClient.exists(beforeNodeLocal.get())) { try { countDownLatch.await(); } catch (InterruptedException e) { e.printStackTrace(); } } zkClient.unsubscribeDataChanges(beforeNodeLocal.get(), iZkDataListener); } 解锁过程: /** * @Author: yuenbin * @Date :2020/9/16 * @Time :16:44 * @Motto: It is better to be clear than to be clever ! * @Destrib: 给节点解锁 **/ public void unlock() { try { zkClient.delete(currentNodeLocal.get()); System.out.println(currentNodeLocal.get() + "释放锁成功"); } catch (Exception e) { e.printStackTrace(); } } 模拟多线程任务 static class Task implements Runnable { private CountDownLatch count ; public Task(CountDownLatch count){ this.count=count; } @Override public void run() { DistrLockByZookeeper distrLockByZookeeper = new DistrLockByZookeeper(); distrLockByZookeeper.getLock(""); while (sum > 0 ) { try { System.out.println("线程" + Thread.currentThread().getName() + "\t正在卖第" + (sum--) + "张票"); } catch (Exception ex) { } finally { distrLockByZookeeper.unlock(); } try { Thread.sleep(1000); } catch (InterruptedException e) { e.printStackTrace(); } } count.countDown(); } } main 方法展示 public static void main(String[] args) { CountDownLatch count = new CountDownLatch(200) ; Task task = new Task(count); for(int i=1;i<=200;i++){ new Thread(task, "pool-"+i).start(); } try { count.await(); if(count.getCount() == 0 ){ System.out.println("全部车票已售完"); } } catch (InterruptedException e) { e.printStackTrace(); } } 主变量定义 protected static ZkClient zkClient = new ZkClient("你的zk:端口", 10000); //定义需要等待的已经持有锁的节点 private static ThreadLocal<String> beforeNodeLocal = new ThreadLocal<>() ; //当前节点路径 private static ThreadLocal<String> currentNodeLocal =new ThreadLocal<>(); private static int sum=999; //根节点 private static String rootNode ="/locks"; //锁类型 private static String lockFlag="-locking-"; private static CountDownLatch countDownLatch =null ; public DistrLockByZookeeper(){ if(!zkClient.exists(rootNode)){ zkClient.createPersistent(rootNode); } } 效果展示: 我这里模拟的是999个车票,200个线程同时跑,模拟真实业务抢票场景,使用zk分布式锁,控制抢票过程,不会出现抢票重复,抢票死锁的现象。如下是效果部分展示 [/locks/0000007507]节点创建成功 [/locks/0000007508]节点创建成功 [/locks/0000007510]节点创建成功 [/locks/0000007512]节点创建成功 [/locks/0000007511]节点创建成功 [/locks/0000007509]节点创建成功 [/locks/0000007513]节点创建成功 节点[/locks/0000007452]正在等待[/locks/0000007451] 节点[/locks/0000007468]正在等待[/locks/0000007467] 节点[/locks/0000007471]正在等待[/locks/0000007470] 线程pool-169 正在卖第999张票 节点[/locks/0000007472]正在等待[/locks/0000007471] 节点[/locks/0000007470]正在等待[/locks/0000007469] 节点[/locks/0000007466]正在等待[/locks/0000007465] [/locks/0000007638]节点创建成功 节点[/locks/0000007469]正在等待[/locks/0000007468] 节点[/locks/0000007473]正在等待[/locks/0000007472] 节点[/locks/0000007465]正在等待[/locks/0000007464] 节点[/locks/0000007463]正在等待[/locks/0000007462] 节点[/locks/0000007464]正在等待[/locks/0000007463] 节点[/locks/0000007462]正在等待[/locks/0000007461] 节点[/locks/0000007461]正在等待[/locks/0000007460] 节点[/locks/0000007460]正在等待[/locks/0000007459] 节点[/locks/0000007456]正在等待[/locks/0000007455] [/locks/0000007637]节点创建成功 [/locks/0000007636]节点创建成功 节点[/locks/0000007459]正在等待[/locks/0000007458] [/locks/0000007635]节点创建成功 节点[/locks/0000007455]正在等待[/locks/0000007454] 节点[/locks/0000007453]正在等待[/locks/0000007452] [/locks/0000007634]节点创建成功 节点[/locks/0000007454]正在等待[/locks/0000007453] 节点[/locks/0000007474]正在等待[/locks/0000007473] 节点[/locks/0000007477]正在等待[/locks/0000007476] 节点[/locks/0000007479]正在等待[/locks/0000007478] 节点[/locks/0000007478]正在等待[/locks/0000007477] 节点[/locks/0000007481]正在等待[/locks/0000007480] 节点[/locks/0000007482]正在等待[/locks/0000007481] 节点[/locks/0000007483]正在等待[/locks/0000007482] 节点[/locks/0000007484]正在等待[/locks/0000007483] 节点[/locks/0000007485]正在等待[/locks/0000007484] 节点[/locks/0000007486]正在等待[/locks/0000007485] 节点[/locks/0000007487]正在等待[/locks/0000007486] [/locks/0000007633]节点创建成功 节点[/locks/0000007488]正在等待[/locks/0000007487] [/locks/0000007632]节点创建成功 节点[/locks/0000007490]正在等待[/locks/0000007489] 节点[/locks/0000007489]正在等待[/locks/0000007488] 节点[/locks/0000007491]正在等待[/locks/0000007490] 节点[/locks/0000007492]正在等待[/locks/0000007491] 节点[/locks/0000007493]正在等待[/locks/0000007492] [/locks/0000007631]节点创建成功 节点[/locks/0000007494]正在等待[/locks/0000007493] 节点[/locks/0000007495]正在等待[/locks/0000007494] 节点[/locks/0000007496]正在等待[/locks/0000007495] 节点[/locks/0000007497]正在等待[/locks/0000007496] 节点[/locks/0000007499]正在等待[/locks/0000007498] 节点[/locks/0000007498]正在等待[/locks/0000007497] 节点[/locks/0000007502]正在等待[/locks/0000007501] 节点[/locks/0000007503]正在等待[/locks/0000007502] 节点[/locks/0000007501]正在等待[/locks/0000007500] 节点[/locks/0000007504]正在等待[/locks/0000007503] 节点[/locks/0000007505]正在等待[/locks/0000007504] 节点[/locks/0000007506]正在等待[/locks/0000007505] 节点[/locks/0000007508]正在等待[/locks/0000007507] [/locks/0000007639]节点创建成功 [/locks/0000007641]节点创建成功 [/locks/0000007642]节点创建成功 [/locks/0000007643]节点创建成功 [/locks/0000007644]节点创建成功 [/locks/0000007645]节点创建成功 [/locks/0000007646]节点创建成功 [/locks/0000007647]节点创建成功 [/locks/0000007648]节点创建成功 [/locks/0000007649]节点创建成功 [/locks/0000007650]节点创建成功 节点[/locks/0000007512]正在等待[/locks/0000007511] 节点[/locks/0000007511]正在等待[/locks/0000007510] 节点[/locks/0000007509]正在等待[/locks/0000007508] 节点[/locks/0000007513]正在等待[/locks/0000007512] 节点[/locks/0000007637]正在等待[/locks/0000007636] 节点[/locks/0000007633]正在等待[/locks/0000007632] 节点[/locks/0000007632]正在等待[/locks/0000007631] [/locks/0000007630]节点创建成功 线程pool-120 正在卖第802张票 线程pool-121 正在卖第803张票 线程pool-165 正在卖第804张票 线程pool-122 正在卖第805张票 线程pool-126 正在卖第806张票 /locks/0000007513释放锁成功 线程pool-132 正在卖第807张票 线程pool-23 正在卖第808张票 线程pool-127 正在卖第809张票 线程pool-118 正在卖第810张票 线程pool-123 正在卖第811张票 线程pool-119 正在卖第812张票 /locks/0000007506释放锁成功 线程pool-2 正在卖第813张票 线程pool-166 正在卖第814张票 线程pool-164 正在卖第815张票 线程pool-130 正在卖第816张票 线程pool-134 正在卖第817张票 线程pool-117 正在卖第818张票 线程pool-116 正在卖第819张票 线程pool-115 正在卖第820张票 线程pool-128 正在卖第821张票 线程pool-129 正在卖第822张票 /locks/0000007636释放锁成功 /locks/0000007500释放锁成功 /locks/0000007457释放锁成功 线程pool-114 正在卖第823张票 线程pool-131 正在卖第824张票 线程pool-113 正在卖第825张票 线程pool-133 正在卖第826张票 线程pool-144 正在卖第827张票 线程pool-112 正在卖第828张票 线程pool-111 正在卖第829张票 线程pool-105 正在卖第830张票 线程pool-145 正在卖第831张票 线程pool-107 正在卖第832张票 线程pool-146 正在卖第833张票 线程pool-104 正在卖第834张票 线程pool-103 正在卖第835张票 线程pool-147 正在卖第835张票 线程pool-56 正在卖第836张票 线程pool-149 正在卖第837张票 线程pool-102 正在卖第838张票 线程pool-106 正在卖第839张票 线程pool-74 正在卖第840张票 线程pool-83 正在卖第841张票 线程pool-84 正在卖第842张票 线程pool-76 正在卖第843张票 线程pool-64 正在卖第844张票 线程pool-85 正在卖第845张票 线程pool-90 正在卖第846张票 线程pool-92 正在卖第847张票 线程pool-87 正在卖第848张票 线程pool-96 正在卖第849张票 线程pool-88 正在卖第850张票 线程pool-95 正在卖第851张票 线程pool-86 正在卖第852张票 线程pool-89 正在卖第853张票 线程pool-93 正在卖第854张票 线程pool-97 正在卖第855张票 线程pool-91 正在卖第856张票 线程pool-94 正在卖第857张票 线程pool-99 正在卖第858张票 线程pool-110 正在卖第859张票 线程pool-98 正在卖第860张票 线程pool-101 正在卖第861张票 线程pool-100 正在卖第862张票 线程pool-108 正在卖第863张票 线程pool-109 正在卖第864张票 线程pool-52 正在卖第865张票 线程pool-39 正在卖第866张票 线程pool-75 正在卖第867张票 线程pool-63 正在卖第868张票 线程pool-51 正在卖第869张票 线程pool-81 正在卖第870张票 线程pool-19 正在卖第871张票 线程pool-78 正在卖第872张票 线程pool-50 正在卖第873张票 线程pool-79 正在卖第874张票 线程pool-80 正在卖第875张票 线程pool-12 正在卖第876张票 线程pool-31 正在卖第877张票 线程pool-82 正在卖第878张票 线程pool-53 正在卖第879张票 线程pool-22 正在卖第880张票 线程pool-77 正在卖第881张票 线程pool-13 正在卖第882张票 线程pool-11 正在卖第883张票 线程pool-54 正在卖第884张票 线程pool-21 正在卖第885张票 线程pool-58 正在卖第886张票 线程pool-24 正在卖第887张票 线程pool-49 正在卖第888张票 线程pool-14 正在卖第889张票 线程pool-10 正在卖第890张票 线程pool-20 正在卖第891张票 线程pool-55 正在卖第892张票 线程pool-59 正在卖第893张票 线程pool-57 正在卖第894张票 线程pool-48 正在卖第895张票 线程pool-25 正在卖第896张票 线程pool-199 正在卖第897张票 线程pool-60 正在卖第898张票 线程pool-16 正在卖第899张票 线程pool-9 正在卖第900张票 线程pool-61 正在卖第901张票 线程pool-26 正在卖第902张票 线程pool-65 正在卖第903张票 线程pool-46 正在卖第904张票 线程pool-66 正在卖第905张票 线程pool-8 正在卖第906张票 线程pool-67 正在卖第907张票 线程pool-45 正在卖第908张票 线程pool-68 正在卖第909张票 线程pool-27 正在卖第910张票 线程pool-69 正在卖第911张票 线程pool-47 正在卖第912张票 线程pool-70 正在卖第913张票 线程pool-44 正在卖第914张票 线程pool-71 正在卖第915张票 线程pool-7 正在卖第916张票 线程pool-72 正在卖第917张票 线程pool-38 正在卖第918张票 线程pool-30 正在卖第919张票 线程pool-137 正在卖第920张票 线程pool-73 正在卖第921张票 线程pool-198 正在卖第922张票 线程pool-187 正在卖第923张票 线程pool-18 正在卖第924张票 线程pool-15 正在卖第925张票 线程pool-161 正在卖第926张票 线程pool-150 正在卖第927张票 线程pool-179 正在卖第928张票 线程pool-196 正在卖第929张票 线程pool-167 正在卖第930张票 线程pool-193 正在卖第931张票 线程pool-154 正在卖第932张票 线程pool-135 正在卖第933张票 线程pool-159 正在卖第934张票 线程pool-188 正在卖第935张票 线程pool-6 正在卖第16张票 线程pool-163 正在卖第15张票 线程pool-28 正在卖第14张票 线程pool-152 正在卖第13张票 /locks/0000007485释放锁成功 /locks/0000007460释放锁成功 线程pool-143 正在卖第7张票 线程pool-182 正在卖第8张票 线程pool-34 正在卖第9张票 线程pool-158 正在卖第10张票 线程pool-29 正在卖第11张票 线程pool-33 正在卖第12张票 /locks/0000007630释放锁成功 /locks/0000007465释放锁成功 /locks/0000007456释放锁成功 /locks/0000007464释放锁成功 /locks/0000007466释放锁成功 /locks/0000007469释放锁成功 /locks/0000007638释放锁成功 /locks/0000007483释放锁成功 /locks/0000007507释放锁成功 /locks/0000007508释放锁成功 /locks/0000007481释放锁成功 /locks/0000007644释放锁成功 /locks/0000007454释放锁成功 /locks/0000007453释放锁成功 /locks/0000007477释放锁成功 /locks/0000007631释放锁成功 /locks/0000007635释放锁成功 /locks/0000007474释放锁成功 /locks/0000007510释放锁成功 /locks/0000007451释放锁成功 /locks/0000007511释放锁成功 /locks/0000007478释放锁成功 /locks/0000007509释放锁成功 /locks/0000007641释放锁成功 /locks/0000007479释放锁成功 /locks/0000007634释放锁成功 /locks/0000007639释放锁成功 线程pool-177 正在卖第6张票 /locks/0000007452释放锁成功 线程pool-36 正在卖第5张票 线程pool-174 正在卖第4张票 /locks/0000007636释放锁成功 线程pool-125 正在卖第2张票 线程pool-157 正在卖第1张票 线程pool-138 正在卖第3张票 /locks/0000007506释放锁成功 /locks/0000007457释放锁成功 /locks/0000007513释放锁成功 /locks/0000007500释放锁成功 全部车票已售完 我该怎么选择呢? 我想各位读者一定也会遇到类似的问题,在真实业务场景中,我们该如何进行抉择,该选择什么样的分布式锁实现方式呢?上文通过具体的实例、效果展示、验证等简单的总结如下,其实各有千秋,各有优缺: 常用分布式锁实现比较 类型 性能 支持的锁 线程阻塞 高并发 效率 mysql 较弱 乐观锁 较弱,容易锁表 最低 redis 最强 既可以是公平锁也可以是非公平锁 非阻塞 最强 最高 zookeeper 中等 公平锁 既可以是阻塞也可以是非阻塞 最大可支持10亿个节点 中间 其实通过比较就能看出来,zk在高并发业务场景中还是逊色于redis的实现,而redis由于是在内存层级工作,因此效率是最高的。数据库实现分布式锁 除了mysql以外,oracle也可以实现,但在高并发,多线程的业务场景中,频繁的I/O可能对业务数据库造成一定的压力,各位还是要谨慎选择。 ok,以上是本人通过实践验证的三种较为常见的分布式锁的实现,各位读者如果有不同的见解欢迎各位来信指导!

优秀的个人博客,低调大师

源代码加密软件技术原理、未来趋势与部署实践

摘要:源代码是软件企业的核心资产,其防泄密需求远高于普通文档。源代码加密软件并非简单“给文件加个密码”,而是以透明加密、进程信任、驱动级过滤、外发审批和审计追溯为核心的一体化数据防泄漏体系。本文从技术原理、底层逻辑、附加功能与部署方式四个维度展开,并以一个源代码加密软件为例,说明此类系统在企业中的典型落地方式。

优秀的个人博客,低调大师

反射内存技术发展趋势与国产化替代

反射内存网络诞生于上世纪九十年代(如 VMIC 的 5587 系列),至今已走过三十余年。在以太网、InfiniBand、TSN 等新技术层出不穷的今天,反射内存在飞行仿真、军工测控、实时控制等硬实时领域依然占据不可替代的位置。它的生命力来自一个朴素的判断:对微秒级确定性通信而言,把网络伪装成内存,仍是最简单、最可靠的工程方案。展望未来,反射内存正沿着"性能提升、形态演进、自主可控"三条主线发展。

资源下载

更多资源
腾讯云软件源

腾讯云软件源

为解决软件依赖安装时官方源访问速度慢的问题,腾讯云为一些软件搭建了缓存服务。您可以通过使用腾讯云软件源站来提升依赖包的安装速度。为了方便用户自由搭建服务架构,目前腾讯云软件源站支持公网访问和内网访问。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Spring

Spring

Spring框架(Spring Framework)是由Rod Johnson于2002年提出的开源Java企业级应用框架,旨在通过使用JavaBean替代传统EJB实现方式降低企业级编程开发的复杂性。该框架基于简单性、可测试性和松耦合性设计理念,提供核心容器、应用上下文、数据访问集成等模块,支持整合Hibernate、Struts等第三方框架,其适用范围不仅限于服务器端开发,绝大多数Java应用均可从中受益。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册