并发环境下进行编程时,需要使用锁机制来同步多线程间的操作,保证共享资源的互斥访问。加锁会带来性能上的损坏,似乎是众所周知的事情。然而,加锁本身不会带来多少的性能消耗,性能主要是在线程的获取锁的过程。如果只有一个线程竞争锁,此时并不存在多线程竞争的情况,那么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; }

@Override
public void run() {
    super.run();
    lockMethod.busiA();
}

}

BUSSB是线程类,用来处理B业务,调用的是LockMethod的busiB()方法: public class BUSSB extends Thread { LockMethod lockMethod; void deal(LockMethod lockMethod){ this.lockMethod = lockMethod; }

@Override
public 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){

  }

  • 1
  • 2

}

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

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(); } }

具有1-5工作经验的,面对目前流行的技术不知从何下手,需要突破技术瓶颈的可以加群。在公司待久了,过得很安逸,但跳槽时面试碰壁。需要在短时间内进修、跳槽拿高薪的可以加群。如果没有工作经验,但基础非常扎实,对java工作机制,常用设计思想,常用java开发框架掌握熟练的可以加群。java架构群:697579751 一起交流

java多线程编程——锁优化的更多相关文章

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

      阅读目录 一.尽量不要锁住方法 二.缩小同步代码块,只锁数据 三.锁中尽量不要再包含锁 四.将锁私有化,在内部管理锁 五.进行适当的锁分解 正文 并发环境下进行编程时,需要使用锁机制来同步多线程间 ...

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

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

  3. Java多线程之锁优化策略

    转载请注明原文地址:http://www.cnblogs.com/ygj0930/p/6561264.html  锁的优化策略 编码过程中可采取的锁优化的思路有以下几种: 1:减少锁持有时间 例如:对 ...

  4. Java多线程编程详解

    转自:http://programming.iteye.com/blog/158568 线程的同步 由于同一进程的多个线程共享同一片存储空间,在带来方便的同时,也带来了访问冲突这个严重的问题.Ja ...

  5. Java多线程编程实战指南(核心篇)读书笔记(五)

    (尊重劳动成果,转载请注明出处:http://blog.csdn.net/qq_25827845/article/details/76730459冷血之心的博客) 博主准备恶补一番Java高并发编程相 ...

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

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

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

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

  8. 《Java多线程编程实战指南(核心篇)》阅读笔记

    <Java多线程编程实战指南(核心篇)>阅读笔记 */--> <Java多线程编程实战指南(核心篇)>阅读笔记 Table of Contents 1. 线程概念 1.1 ...

  9. Java多线程编程实战02:多线程编程模型

    多线程编程模型 线程安全名词 串行.并发和并行 串行:一个人,将任务一个一个完成 并发:一个人,有策略地同时做多件事情 并行:多个人,每人做一个事情 竞态 名词 竞态:计算结果的正确性与时间有关的现象 ...

随机推荐

  1. 【编程技巧】NSDate,NSDateFormatter,NSTimeInterval

    //获取日期 todaysDate=[NSDate date]; //显示日期和时间 dateFormat = [[NSDateFormatter alloc] init];//NSDate没有自己的 ...

  2. 运行android程序的时分出现了No compatible targets were found.Do you wish to.

    这个错误是说明没有android虚拟机,那么新建一个就OK了. 假如出现了这个状况,就点击yes,然后new一个. 具体方案如下,(可自定义.仅供参考)

  3. 免费内网映射外网绑定,tcp端口转发(windows)

    在tcp socket开发过程中,想要外网客户端映射到本地启动的tcp服务端,总结本地tcp端口映射外网方法: 1.打开ngrok后注册用户,网址 ngrok:https://www.ngrok.cc ...

  4. Vuejs 安装与配置

    1.全局安装 vue-cli $ npm install --global vue-cli 2.创建一个基于 webpack 模板的新项目 $ vue init webpack my-project ...

  5. Asp.net core 2.0.1 Razor 的使用学习笔记(三)

    ASP.net core 2.0.0 中 asp.net identity 2.0.0 的基本使用(二)—用户账户及cookie配置 修改用户账户及cookie配置 一.修改密码强度和用户邮箱验证规则 ...

  6. ORACLE对象大小写问题

    在数据库新建一个测试表(数据库版本为ORACLE 10.2.0.1.0),表名为小写的test. 脚本如下所示: CREATE TABLE test(     id      NUMBER(10),  ...

  7. rem与@media 的优缺点

    首先:   如果我们在做单独移动端网站或者app的时候  我建议  使用 rem  ; 他能让我们在手机各个机型的适配方面:大大减少我们代码的重复性,是我们的代码更兼容. 下面两个图一个调试在常用的机 ...

  8. PHP date()函数详解

    date (PHP 4, PHP 5) date - 格式化一个本地时间/日期 说明¶ string date ( string $format [, int $timestamp ] ) 返回将整数 ...

  9. HashMap原理总结

    来总结一下HashMap的原理 1.HashMap当中有一个内部类,它叫Node,然后这个Node呢,它其实是实现了Map.Entry接口,这个接口当中有几个抽象的方法和几个具体的方法.其中Map.E ...

  10. 图说:为什么Java中的字符串被定义为不可变的

    8张图,看懂Java字符串的不变性 字符串,想必大家最熟悉不过了,通常我们在代码中有几种方式可以创建字符串,比如:String s = "Hollis";这时,其实会在堆内存中创建 ...