改善Java中锁的性能

发表于:2015-3-31 10:26

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:飘扬叶    来源:51Testing软件测试网采编

  两个月前向Plumbr公司引进线程死锁的检测之后,我们开始收到一些类似于这样的询问:“棒极了!现在我知道造成程序出现性能问题的原因了,但是接下来该怎么做呢?”
  我们努力为自己的产品所遇到的问题思考解决办法,但在这篇文章中我将给大家分享几种常用的技术,包括分离锁、并行数据结构、保护数据而非代码、缩小锁的作用范围,这几种技术可以使我们不使用任何工具来检测死锁。
  锁不是问题的根源,锁之间的竞争才是
  通常在多线程的代码中遇到性能方面的问题时,一般都会抱怨是锁的问题。毕竟锁会降低程序的运行速度和其较低的扩展性是众所周知的。因此,如果带着这种“常识”开始优化代码,其结果很有可能是在之后会出现讨人厌的并发问题。
  因此,明白竞争锁和非竞争锁的不同是非常重要的。当一个线程试图进入 另一个线程正在执行的同步块或方法时会触发锁竞争。该线程会被强制进入等待状态,直到第一个线程执行完同步块并且已经释放了监视器。当同一时间只有一个线 程尝试执行同步的代码区域时,锁会保持非竞争的状态。
  事实上,在非竞争的情况下和大多数的应用中,JVM已经对同步进行了优化。非竞争锁在执行过程中不会带来任何额外的开销。因此,你不应该因为性能问题抱怨锁,应该抱怨的是锁的竞争。当有了这个认识之后,让我们来看下能做些什么,以降低竞争的可能性或减少竞争的持续时间。
  保护数据而非代码
  解决线程安全问题的一个快速的方法就是对整个方法的可访问性加锁。例如下面这个例子,试图通过这种方法来建立一个在线扑克游戏服务器:
  class GameServer {
  public Map<<String, List<Player>> tables = new HashMap<String, List<Player>>();
  public synchronized void join(Player player, Table table) {
  if (player.getAccountBalance() > table.getLimit()) {
  List<Player> tablePlayers = tables.get(table.getId());
  if (tablePlayers.size() < 9) {
  tablePlayers.add(player);
  }
  }
  }
  public synchronized void leave(Player player, Table table) {/*body skipped for brevity*/}
  public synchronized void createTable() {/*body skipped for brevity*/}
  public synchronized void destroyTable(Table table) {/*body skipped for brevity*/}
  }
  作者的意图是好的——当一个新的玩家加入牌桌 时,必须确保牌桌上的玩家个数不会超过牌桌可以容纳的玩家总个数9。
  但是这种解决办法事实上无论何时都要对玩家进入牌桌进行控制——即使是在服务器的访问量较小的时候也是这样,那些等 待锁释放的线程注定会频繁的触发系统的竞争事件。包含对账户余额和牌桌限制检查的锁定块很可能大幅提高调用操作的开销,而这无疑会增加竞争的可能性和持续 时间。
  解决的第一步就是确保我们保护的是数据,而不是从方法声明移到方法体中的那段同步声明。对于上面那个简单的例子来说,可能改变不大。但是我们要站在整个游戏服务的接口之上来考虑,而不是单单的一个join()方法。
class GameServer {
public Map<String, List<Player>> tables = new HashMap<String, List<Player>>();
public void join(Player player, Table table) {
synchronized (tables) {
if (player.getAccountBalance() > table.getLimit()) {
List<Player> tablePlayers = tables.get(table.getId());
if (tablePlayers.size() < 9) {
tablePlayers.add(player);
}
}
}
}
public void leave(Player player, Table table) {/* body skipped for brevity */}
public void createTable() {/* body skipped for brevity */}
public void destroyTable(Table table) {/* body skipped for brevity */}
}
21/212>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号