tryLock的一个使用示例

就算是有几年工作经验的,如果没有专业的训练,也不一定能写出一手线程安全的代码,对于一般的web开发而言,多线程相关的部分都封装在web server里了,而平时的业务开发不涉及这些高级特性。这是一件好事,因为这样将程序员的注意力都集中在与公司收入直接相关的业务逻辑层,而不需要关注比较复杂的技术层面,但是对程序员个人提升上也有不利的一面,通用的复杂技术都被封装了,程序员工作的技术性也相应降低。所以这需要我们在业余时间不断充电,训练,并且在工作上把握一切提升自我的机会。

以前做过一个爬虫项目,每天要抓取大量的商品数据,但是一些知名电商网站往往会设置各种限制,其中一个限制就是ip黑名单,网站会识别一些有爬虫机器特征的访问来源ip,并计入黑名单,下次爬取就会设置各种关卡,其中一个应对方法就是动态变更ip,方法如下:

 public int changeIPBySh() {
 try {
  logger.error("execute shell command ");
Worker.execute();
 } catch (Exception e) {
 logger.error("Error when process changeIp work" + e.getMessage(), e);
  }
 return 0;
 }

原有程序是通过shell脚本变更ip地址的,由于是多线程运行的,经常会有多个线程同时执行脚本的情况,我们很快就会想到加锁。

 public int changeIPBySh() {
 try {
  synchronized(this){
 logger.error("execute shell command ");
Worker.execute();
 }
  } catch (Exception e) {
 logger.error("Error when process changeIp work" + e.getMessage(), e);
  }
 return 0;
 }

但是这并没有什么卵用,当一个线程执行完脚本解锁后,原来在对象锁等待的线程会获得锁,进而再次执行脚本,这导致一些无谓的ip变更,而且在变更过程中,会影响其他线程的内容抓取。我们的目标是保证在同一时刻只有一个线程变更ip,变更时,新的线程不再等待释放锁,也不重复执行变更脚本。tryLock就可以实现这一目标。

private int changeIPByShdd() {
 boolean captured = lock.tryLock();
 try {
 if (captured) {
 logger.error("execute shell command ");
Worker.execute();
   } else {
    Thread.sleep(sleepTime);
   }
  } catch (Exception e) {
 logger.error("Error when process changeIp work" + e.getMessage(), e);
  } finally {
 if (captured) {
  lock.unlock();
   }
  }
 return 0;
 }

使用tryLock,如果获取了锁则返回true,执行脚本,如果没有,则立即返回false,线程进入休眠。而使用synchronized则会一直等待锁的释放,在语义tryLock提供了一种更适合当前场景的机制。

从广泛的层面而言,使用synchronized,一旦发生死锁,只能重启应用,而tryLock却可以避免一些偶发的死锁。synchronized是在jvm层实现的,发生了异常会自动释放锁,但是tryLock是在代码层面实现的,需要自己释放锁:

finally {
 if (captured) {
  lock.unlock();
   }
}

原文发布于微信公众号 - java达人(drjava)

原文发表时间:2016-08-06

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

来自专栏芋道源码1024

Dubbo 源码解析 —— 集群容错架构设计

前言 本来是想把整个dubbo源码解析一次性弄完,再做成一个系列来发布的,但是正巧最近有位好朋友要去杭州面试,就和我交流了一下.本着对dubbo源码略有心得的心...

32570
来自专栏PPV课数据科学社区

大规模爬虫流程总结

爬虫是一个比较容易上手的技术,也许花5分钟看一篇文档就能爬取单个网页上的数据。但对于大规模爬虫,完全就是另一回事,并不是1*n这么简单,还会衍生出许多别的问题。...

382110
来自专栏Bug生活2048

这些数据库,你都用过吗

关系型数据库模型是把复杂的数据结构归结为简单的二元关系(即二维表格形式)。在关系型数据库中,对数据的操作几乎全部建立在一个或多个关系表格上,通过对这些关联的表格...

17910
来自专栏北京马哥教育

让弹幕文明一点的Python屏蔽功能小实验

突然想到一个视频里面弹幕被和谐的一满屏的*号觉得很有趣,然后就想用python来试试写写看,结果还真玩出了点效果,思路是首先你得有一个脏话存放的仓库好到时候检测...

32550
来自专栏iOS技术

设计一个简单的 iOS 架构前言一、关于组件化二、模块化思维划分文件三、减少全局宏的使用四、去基类化设计五、MVC?MVP?MVVM?VIPER?结语

正如“100个读者就有100个哈姆雷特”一样,对于架构的理解不同的软件工程师有不同的看法。架构设计往往是一个权衡的过程,每一个架构设计者都要考虑到各个因素,比如...

17630
来自专栏Java技术栈

同样是5年的开发经验,差距在哪里了?

我现在就职于一家中型的互联网企业,去年年底入职的薪资和待遇都很不错,但是总结起来说的好听就是全村人的希望,说的不好听就是一个人几乎干了一个项目组的事。

11360
来自专栏量化投资与机器学习

战斗民族开源神器ClickHouse:一款适合于构建量化回测研究系统的高性能列式数据库(一)

编辑部原创 编译:wally21st、 西西 未经允许,不得转载 对于一些私募、投资机构和个人来说,量化投资研究、回测离不开数据的支持。当数据量达到一定数量,如...

73880
来自专栏程序人生

系统开发之设计模式

上周五同事分享了design patterns in networks,里面很多patterns都是做路由器防火墙这样的转发设备之所以高效的精髓所在。「程序人生...

35450
来自专栏java工会

使用Github创建自己的小博客

10620
来自专栏编程一生

架构师之路--搜索业务和技术介绍及容错机制

13920

扫码关注云+社区

领取腾讯云代金券