并发环境下进行编程时,需要使用锁机制来同步多线程间的操作,保证共享资源的互斥访问。加锁会带来性能上的损坏,似乎是众所周知的事情。然而,加锁本身不会带来多少的性能消耗,性能主要是在线程的获取锁的过程。如果只有一个线程竞争锁,此时并不存在多线程竞争的情况,那么JVM会进行优化,那么这时加锁带来的性能消耗基本可以忽略。因此,规范加锁的操作,优化锁的使用方法,避免不必要的线程竞争,不仅可以提高程序性能,也能避免不规范加锁可能造成线程死锁问题,提高程序健壮性。下面阐述几种锁优化的思路。

一、尽量不要锁住方法

在普通成员函数上加锁时,线程获得的是该方法所在对象的对象锁。此时整个对象都会被锁住。这也意味着,如果这个对象提供的多个同步方法是针对不同业务的,那么由于整个对象被锁住,一个业务业务在处理时,其他不相关的业务线程也必须wait。下面的例子展示了这种情况:

LockMethod类包含两个同步方法,分别在两种业务处理中被调用:

public class LockMethod   {public synchronized void busiA() {for (int i = 0; i < 10000; i++) {System.out.println(Thread.currentThread().getName() + "deal with bussiness A:"+i);}}public synchronized void busiB() {for (int i = 0; i < 10000; i++) {System.out.println(Thread.currentThread().getName() + "deal with bussiness B:"+i);}}
}

BUSSA是线程类,用来处理A业务,调用的是LockMethod的busiA()方法:

public class BUSSA extends Thread {LockMethod lockMethod;void deal(LockMethod lockMethod){this.lockMethod = lockMethod;}@Overridepublic void run() {super.run();lockMethod.busiA();}
}

BUSSB是线程类,用来处理B业务,调用的是LockMethod的busiB()方法:

public class BUSSB extends Thread {LockMethod lockMethod;void deal(LockMethod lockMethod){this.lockMethod = lockMethod;}@Overridepublic void run() {super.run();lockMethod.busiB();}
}

TestLockMethod类,使用线程BUSSA与BUSSB进行业务处理:

public class TestLockMethod extends Thread {public static void main(String[] args) {LockMethod lockMethod = new LockMethod();BUSSA bussa = new BUSSA();BUSSB bussb = new BUSSB();bussa.deal(lockMethod);bussb.deal(lockMethod);bussa.start();bussb.start();}
}

运行程序,可以看到在线程bussa 执行的过程中,bussb是不能够进入函数 busiB()的,因为此时lockMethod 的对象锁被线程bussa获取了。

二、缩小同步代码块,只锁数据

有时候为了编程方便,有些人会synchnoized很大的一块代码,如果这个代码块中的某些操作与共享资源并不相关,那么应当把它们放到同步块外部,避免长时间的持有锁,造成其他线程一直处于等待状态。尤其是一些循环操作、同步I/O操作。不止是在代码的行数范围上缩小同步块,在执行逻辑上,也应该缩小同步块,例如多加一些条件判断,符合条件的再进行同步,而不是同步之后再进行条件判断,尽量减少不必要的进入同步块的逻辑。

三、锁中尽量不要再包含锁

这种情况经常发生,线程在得到了A锁之后,在同步方法块中调用了另外对象的同步方法,获得了第二个锁,这样可能导致一个调用堆栈中有多把锁的请求,多线程情况下可能会出现很复杂、难以分析的异常情况,导致死锁的发生。下面的代码显示了这种情况:

synchronized(A){synchronized(B){}
}

或是在同步块中调用了同步方法:

synchronized(A){B  b = objArrayList.get(0);b.method(); //这是一个同步方法
}

解决的办法是跳出来加锁,不要包含加锁:

{B b = null;synchronized(A){b = objArrayList.get(0);}b.method();
}

四、将锁私有化,在内部管理锁

把锁作为一个私有的对象,外部不能拿到这个对象,更安全一些。对象可能被其他线程直接进行加锁操作,此时线程便持有了该对象的对象锁,例如下面这种情况:

class A {public void method1() {}
}class B {public void method1() {A a = new A();synchronized (a) { //直接进行加锁      a.method1();
        }}
}

这种使用方式下,对象a的对象锁被外部所持有,让这把锁在外部多个地方被使用是比较危险的,对代码的逻辑流程阅读也造成困扰。一种更好的方式是在类的内部自己管理锁,外部需要同步方案时,也是通过接口方式来提供同步操作:

class A {private Object lock = new Object();public void method1() {synchronized (lock){}}
}class B {public void method1() {A a = new A();a.method1();}
}

五、进行适当的锁分解

考虑下面这段程序:

public class GameServer {public Map<String, List<Player>> tables = new HashMap<String, List<Player>>();public void join(Player player, Table table) {if (player.getAccountBalance() > table.getLimit()) {synchronized (tables) {List<Player> tablePlayers = tables.get(table.getId());if (tablePlayers.size() < 9) {tablePlayers.add(player);}}}}public void leave(Player player, Table table) {/*省略*/} public void createTable() {/*省略*/} public void destroyTable(Table table) {/*省略*/}
}

在这个例子中,join方法只使用一个同步锁,来获取tables中的List<Player>对象,然后判断玩家数量是不是小于9,如果是,就调增加一个玩家。当有成千上万个List<Player>存在tables中时,对tables锁的竞争将非常激烈。在这里,我们可以考虑进行锁的分解:快速取出数据之后,对List<Player>对象进行加锁,让其他线程可快速竞争获得tables对象锁:

public class GameServer {public Map<String, List<Player>> tables = new HashMap<String, List<Player>>();public void join(Player player, Table table) {if (player.getAccountBalance() > table.getLimit()) {List<Player> tablePlayers = null;synchronized (tables) {tablePlayers = tables.get(table.getId());}synchronized (tablePlayers) {if (tablePlayers.size() < 9) {tablePlayers.add(player);}}}}public void leave(Player player, Table table) {/*省略*/} public void createTable() {/*省略*/} public void destroyTable(Table table) {/*省略*/}
}

(完)

我的博客即将搬运同步至腾讯云+社区,邀请大家一同入驻:https://cloud.tencent.com/developer/support-plan?invite_code=2da2gtpfllwkk

转载于:https://www.cnblogs.com/QG-whz/p/8351298.html

Java多线程编程—锁优化相关推荐

  1. Java多线程编程 — 锁优化

    2019独角兽企业重金招聘Python工程师标准>>> 阅读目录 一.尽量不要锁住方法 二.缩小同步代码块,只锁数据 三.锁中尽量不要再包含锁 四.将锁私有化,在内部管理锁 五.进行 ...

  2. java多线程编程——锁优化

    并发环境下进行编程时,需要使用锁机制来同步多线程间的操作,保证共享资源的互斥访问.加锁会带来性能上的损坏,似乎是众所周知的事情.然而,加锁本身不会带来多少的性能消耗,性能主要是在线程的获取锁的过程.如 ...

  3. java单线程上锁_关于Java多线程编程锁优化的深入学习

    正文 并发环境下进行编程时,需要使用锁机制来同步多线程间的操作,保证共享资源的互斥访问.加锁会带来性能上的损坏,似乎是众所周知的事情.然而,加锁本身不会带来多少的性能消耗,性能主要是在线程的获取锁的过 ...

  4. java多线程编程01---------基本概念

    一. java多线程编程基本概念--------基本概念 java多线程可以说是java基础中相对较难的部分,尤其是对于小白,次一系列文章的将会对多线程编程及其原理进行介绍,希望对正在多线程中碰壁的小 ...

  5. Java多线程编程那些事:volatile解惑--转

    http://www.infoq.com/cn/articles/java-multi-thread-volatile/ 1. 前言 volatile关键字可能是Java开发人员"熟悉而又陌 ...

  6. Java多线程编程:交替打印数字1234和字母abcd

    Java多线程编程:交替打印数字1234和字母abcd 1. 使用synchronized同步锁 2. 使用LockSupport类 2.1 LockSupport介绍 3. 使用AtomicInte ...

  7. Java多线程开发(一)Java多线程编程简介

    文章目录 参考 Java线程简介 Thread类构造方法和属性 常用Thread类方法 线程的生命周期 多线程编程的优势和风险 安全性问题 活跃性问题 性能问题 参考 [Java并发系列01]Thre ...

  8. Java 多线程编程核心技术

    课程介绍 多线程编程在最大限度利用计算资源.提高软件服务质量方面扮演着至关重要的角色,而掌握多线程编程也成为了广大开发人员所必须要具备的技能. 本课程以基本概念.原理方法为主线,每篇文章结合大量演示实 ...

  9. Java多线程编程模式实战指南(二):Immutable Object模式--转载

    本文由本人首次发布在infoq中文站上:http://www.infoq.com/cn/articles/java-multithreaded-programming-mode-immutable-o ...

最新文章

  1. centos使用镜像源轻松配置golang+vscode的方法
  2. 微信小程序制作-随笔2
  3. MyEclipse+JavaEE+jsp+sqlsever实现产品售后服务系统
  4. C++(STL):17---deque之迭代器使用
  5. python的数据结构
  6. SQL基础实例(学生课程系统)
  7. 手机虚拟摄像头_新游 | 打破次元壁障,《猪猪侠AR虚拟使命》现实约战,一切尽在创酷互动!...
  8. 政府网站防篡改解决方案
  9. Win10 如何配置JDK环境变量
  10. Linux与BSD中TCP协议栈实现比较
  11. pcb上钽电容丝印图_pcb钽电容正负极该如何识别
  12. 哥德巴赫猜想c#语言,哥德巴赫猜想算法c#实现方法
  13. IDEA Maven下载依赖时报错: ERROR - #org.jetbrains.idea.maven - Cannot reconnect.
  14. HTPPS的域名部署项目请求头xx_xx问题解决
  15. 核壳油溶性CaSe/CdS/ZnS量子点修饰DADA与MPA-CdSe量子点的制备过程
  16. 头条搜索官网认证说明
  17. 怎么将照片尺寸调整成两寸?照片调整尺寸方法分享
  18. 【算法】Shannon Entropy决策中的香农熵介绍、计算以及python代码实现
  19. C++:实现量化SMM Caplet α 校准测试实例
  20. 陪伴是最长情的告白,民生保险“链”接万家告白征集

热门文章

  1. 因为孤浪的关于爱情...关于婚姻...关于生活... 走进的CTO的第一天
  2. 判断是否为数组的 JavaScript 方法总结
  3. mysql支持数据安全的引擎_MySQL 支持的存储引擎
  4. ORM框架之Mybatis(二)数据库连接池、事务及动态SQL
  5. 知乎App有哪些非常“贴心”的UI设计
  6. PhoneGap在Android上的插件开发方法介绍
  7. android系统耗电如何关闭,安卓手机建议关闭这4大功能,耗电快的罪魁祸首?不用一天三充了...
  8. android parcelable 对象,Android实现Parcelable对象序列化的实例
  9. Scala的初步学习(一)
  10. strategy dynamic参数的使用