在项目开发中, 或许会碰到JAVA的多线程处理, 为保证业务数据的正常, 必须加上锁机制,  常用的处理方法一般是加上synchronized关键字, 目前JDK版本对synchronized已经做了很好的优化,  我们不用再考虑其性能,  但在实际使用中,  往往由于处理不当,  导致系统性能的严重下降, 那么该如何合理的使用synchronized,  必须对其使用方式有个全面了解, 在网上搜寻的资料, 给出的是四种使用方式, 其实可总结为两种, 一个是同步代码块, 一个是同步方法体, 那么该如何使用, 请看下面的测试

  准备两个方法,  对同一个变量做加法, 再对每个方法, 分别开十个线程执行:

  [java]

  public class ThreadUnit

  {

  private int i = 0;

  private Object obj1 = new Object();

  private Object obj2 = new Object();

  public synchronized Integer doAdd1(Long start) throws Exception

  {

  Thread.sleep(100);

  ++i;

  Thread.sleep(100);

  return i;

  }

  public Integer doAdd2(Long start) throws Exception

  {

  Thread.sleep(100);

  ++i;

  Thread.sleep(100);

  return i;

  }

  }

  相关代码:

  [java]

  // 十个线程同时执行方法2

  for (int i = 0; i < 10; i++)

  {

  new Thread(new MessageThread(1, threadUnit))。start();

  }

  // 十个线程同时执行方法2

  for (int j = 0; j < 10; j++)

  {

  new Thread(new MessageThread(2, threadUnit))。start();

  }

  线程处理:

  [java]

  public void run()

  {

  try

  {

  if (operate == 2)

  {

  long start = System.currentTimeMillis();

  int i = threadUnit.doAdd2(start);

  long takeTime = System.currentTimeMillis() - start;

  System.out.println("doAdd2() => i=" + i + ", spendTime=" + takeTime + "ms");

  spendTime += takeTime;

  }

  else

  {

  long start = System.currentTimeMillis();

  int i = threadUnit.doAdd1(start);

  long takeTime = System.currentTimeMillis() - start;

  System.out.println("doAdd1() => i=" + i + ", spendTime=" + takeTime + "ms");

  spendTime += takeTime;

  }

  }

  catch (Exception e)

  {

  e.printStackTrace();

  }

  }

  运行结果:

  1. 在两个方法体上都加上synchronized

  [java]

  public synchronized Integer doAdd1(Long start) throws Exception

  [java]

  public synchronized Integer doAdd2(Long start) throws Exception

  执行结果:

  [html]

  doAdd1() => i=1, spendTime=203ms

  doAdd2() => i=2, spendTime=406ms

  doAdd2() => i=3, spendTime=609ms

  doAdd2() => i=4, spendTime=796ms

  doAdd2() => i=5, spendTime=1000ms

  doAdd2() => i=6, spendTime=1203ms

  doAdd2() => i=7, spendTime=1406ms

  doAdd2() => i=8, spendTime=1609ms

  doAdd2() => i=9, spendTime=1812ms

  doAdd2() => i=10, spendTime=2015ms

  doAdd2() => i=11, spendTime=2218ms

  doAdd1() => i=12, spendTime=2406ms

  doAdd1() => i=13, spendTime=2609ms

  doAdd1() => i=14, spendTime=2812ms

  doAdd1() => i=15, spendTime=3015ms

  doAdd1() => i=16, spendTime=3218ms

  doAdd1() => i=17, spendTime=3421ms

  doAdd1() => i=18, spendTime=3625ms

  doAdd1() => i=19, spendTime=3828ms

  doAdd1() => i=20, spendTime=4015ms

  花费时间:42226ms

  都是有序执行, 变量值没有产生错乱, 但花费时间42226ms

  2.在doAdd1方法上加上synchronized, doAdd2不加。

  [java]

  public synchronized Integer doAdd1(Long start) throws Exception

  执行结果:

  [java]

  doAdd1方法加上synchronized:

  doAdd1() => i=9, spendTime=204ms

  doAdd2() => i=9, spendTime=188ms

  doAdd2() => i=9, spendTime=188ms

  doAdd2() => i=9, spendTime=188ms

  doAdd2() => i=9, spendTime=188ms

  doAdd2() => i=9, spendTime=188ms

  doAdd2() => i=9, spendTime=188ms

  doAdd2() => i=9, spendTime=188ms

  doAdd2() => i=9, spendTime=188ms

  doAdd2() => i=9, spendTime=188ms

  doAdd2() => i=9, spendTime=188ms

  doAdd1() => i=10, spendTime=391ms

  doAdd1() => i=11, spendTime=610ms

  doAdd1() => i=12, spendTime=813ms

  doAdd1() => i=13, spendTime=1016ms

  doAdd1() => i=14, spendTime=1219ms

  doAdd1() => i=15, spendTime=1422ms

  doAdd1() => i=16, spendTime=1610ms

  doAdd1() => i=17, spendTime=1813ms

  doAdd1() => i=18, spendTime=2016ms

  花费时间:12994ms

  doAdd2方法瞬间执行完成, 之后doAdd1方法则是串行有序执行。 这时doAdd2方法获取的变量值已经错乱,  doAdd1获取的正常。  花费时间:12994ms

  3. 两个方法在都没使用synchronized前的情况:

  执行结果:

  [java]

  doAdd1() => i=16, spendTime=203ms

  doAdd1() => i=16, spendTime=203ms

  doAdd1() => i=16, spendTime=203ms

  doAdd1() => i=16, spendTime=203ms

  doAdd1() => i=16, spendTime=203ms

  doAdd1() => i=16, spendTime=203ms

  doAdd1() => i=16, spendTime=203ms

  doAdd1() => i=16, spendTime=203ms

  doAdd1() => i=16, spendTime=203ms

  doAdd2() => i=16, spendTime=203ms

  doAdd2() => i=16, spendTime=203ms

  doAdd2() => i=16, spendTime=203ms

  doAdd1() => i=16, spendTime=203ms

  doAdd2() => i=16, spendTime=203ms

  doAdd2() => i=16, spendTime=203ms

  doAdd2() => i=16, spendTime=203ms

  doAdd2() => i=16, spendTime=203ms

  doAdd2() => i=16, spendTime=203ms

  doAdd2() => i=16, spendTime=203ms

  doAdd2() => i=16, spendTime=203ms

花费时间:4060ms

  可以看到, 两个方法的变量值获取已经错乱,  但花费时间最少4060ms

  4. 使用同步块, 在两个方法内采用不同的对象锁:

  doAdd1:

  [java]

  synchronized (obj1)

  {

  Thread.sleep(100);

  ++i;

  Thread.sleep(100);

  return i;

  }

  doAdd2:

  [java]

  synchronized (obj2)

  {

  Thread.sleep(100);

  ++i;

  Thread.sleep(100);

  return i;

  }

  执行结果:

  [html]

  doAdd1() => i=2, spendTime=203ms

  doAdd2() => i=2, spendTime=203ms

  doAdd1() => i=4, spendTime=406ms

  doAdd2() => i=4, spendTime=406ms

  doAdd1() => i=6, spendTime=609ms

  doAdd2() => i=6, spendTime=609ms

  doAdd1() => i=8, spendTime=812ms

  doAdd2() => i=8, spendTime=812ms

  doAdd1() => i=10, spendTime=1000ms

  doAdd2() => i=10, spendTime=1015ms

  doAdd1() => i=12, spendTime=1203ms

  doAdd2() => i=12, spendTime=1203ms

  doAdd1() => i=14, spendTime=1406ms

  doAdd2() => i=14, spendTime=1406ms

  doAdd1() => i=16, spendTime=1609ms

  doAdd2() => i=16, spendTime=1609ms

  doAdd1() => i=18, spendTime=1812ms

  doAdd2() => i=18, spendTime=1812ms

  doAdd1() => i=20, spendTime=2015ms

  doAdd2() => i=20, spendTime=2015ms

  花费时间:22165ms

  两个方法有序交替执行, 互不影响,  花费时间:22165ms, 相对加锁同一对象执行的时间缩短。

  5. 使用同步块, 使用方法参数作为对象锁:

  [java]

  public Integer doAdd1(Long start) throws Exception

  {

  synchronized (start)

  {

  Thread.sleep(100);

  ++i;

  Thread.sleep(100);

  return i;

  }

  }

  执行结果:

  [java]

  doAdd1() => i=15, spendTime=203ms

  doAdd1() => i=15, spendTime=203ms

  doAdd1() => i=15, spendTime=203ms

  doAdd1() => i=15, spendTime=203ms

  doAdd1() => i=15, spendTime=203ms

  doAdd1() => i=15, spendTime=203ms

  doAdd1() => i=15, spendTime=203ms

  doAdd2() => i=15, spendTime=203ms

  doAdd2() => i=15, spendTime=203ms

  doAdd1() => i=15, spendTime=203ms

  doAdd1() => i=15, spendTime=203ms

  doAdd2() => i=15, spendTime=203ms

  doAdd2() => i=15, spendTime=203ms

  doAdd2() => i=15, spendTime=203ms

  doAdd2() => i=15, spendTime=203ms

  doAdd2() => i=15, spendTime=203ms

  doAdd2() => i=15, spendTime=203ms

  doAdd2() => i=15, spendTime=203ms

  doAdd1() => i=15, spendTime=203ms

  doAdd2() => i=15, spendTime=203ms

  花费时间:4060ms

  执行效果和第三种情况相同,  每个参数作为不同的对象, 即便加上synchronized也不能起到锁的效果。

  6. 把调用的类改为静态类, 只在一个方法上加锁:

  加锁doAdd1方法:

  [java]

  public static synchronized Integer doAdd1(Long start) throws Exception

  执行结果:

  [html]

  doAdd1() => i=9, spendTime=203ms

  doAdd2() => i=9, spendTime=203ms

  doAdd2() => i=9, spendTime=203ms

  doAdd2() => i=9, spendTime=203ms

  doAdd2() => i=9, spendTime=203ms

  doAdd2() => i=9, spendTime=203ms

  doAdd2() => i=9, spendTime=203ms

  doAdd2() => i=9, spendTime=203ms

  doAdd2() => i=9, spendTime=203ms

  doAdd2() => i=9, spendTime=203ms

  doAdd2() => i=9, spendTime=203ms

  doAdd1() => i=10, spendTime=406ms

  doAdd1() => i=11, spendTime=609ms

  doAdd1() => i=12, spendTime=812ms

  doAdd1() => i=13, spendTime=1015ms

  doAdd1() => i=14, spendTime=1218ms

  doAdd1() => i=15, spendTime=1406ms

  doAdd1() => i=16, spendTime=1609ms

  doAdd1() => i=17, spendTime=1812ms

  doAdd1() => i=18, spendTime=2015ms

  花费时间:13135ms

  和第二种情形类似,  没有加锁的doAdd2方法瞬间执行完成,  doAdd1方法则是串行有序执行。

  总结:

  1. synchronized关键在于锁定的对象, 如果是同一对象, 那么所有执行线程, 必须等待对象锁释放后才能执行,  如果是不同对象,  那么只对各对象所关联的线程生效。

  2. synchronized若加在方法体上,  默认锁定的是对象本身。 对于所有加锁的方法,  都是按照串行规则有序执行,  对于没有加锁的方法, 不受任何影响,  静态类同理。

  3. 合理使用synchronized, 既要保证稳定性, 又要保证性能, 需要在两者间作出权衡,  尽量把synchronized范围细度化, 合理控制业务处理流程;  对象操作原子化, 减少锁的使用;

  不要盲目在方法体上加synchronized关键字, 如果每个方法负责处理的是不同业务,  那么尽量采用第四种情形, 使用不同的对象锁处理, 而不是锁定整个对象。

关于JAVA多线程并发synchronized的测试与合理使用的更多相关文章

  1. java 多线程并发 synchronized 同步机制及方式

    2. 锁机制 3. 并发 Excutor框架 4. 并发性与多线程介绍 1. synchronized  参考1. synchronized 分两种方式进行线程的同步:同步块.同步方法 1. 方法同步 ...

  2. Java 多线程并发编程一览笔录

    Java 多线程并发编程一览笔录 知识体系图: 1.线程是什么? 线程是进程中独立运行的子任务. 2.创建线程的方式 方式一:将类声明为 Thread 的子类.该子类应重写 Thread 类的 run ...

  3. Java多线程并发技术

    Java多线程并发技术 参考文献: http://blog.csdn.net/aboy123/article/details/38307539 http://blog.csdn.net/ghsau/a ...

  4. java 多线程并发问题总结

    java 多线程并发主要通过关键字synchronized实现 Java语言的关键字,当它用来修饰一个方法或者一个代码块的时候,能够保证在同一时刻最多只有一个线程执行该段代码. 一.当两个并发线程访问 ...

  5. Java多线程并发05——那么多的锁你都了解了吗

    在多线程或高并发情境中,经常会为了保证数据一致性,而引入锁机制,本文将为各位带来有关锁的基本概念讲解.关注我的公众号「Java面典」了解更多 Java 相关知识点. 根据锁的各种特性,可将锁分为以下几 ...

  6. Java多线程并发07——锁在Java中的实现

    上一篇文章中,我们已经介绍过了各种锁,让各位对锁有了一定的了解.接下来将为各位介绍锁在Java中的实现.关注我的公众号「Java面典」了解更多 Java 相关知识点. 在 Java 中主要通过使用sy ...

  7. Java多线程-并发容器

    Java多线程-并发容器 在Java1.5之后,通过几个并发容器类来改进同步容器类,同步容器类是通过将容器的状态串行访问,从而实现它们的线程安全的,这样做会消弱了并发性,当多个线程并发的竞争容器锁的时 ...

  8. Java多线程-同步:synchronized 和线程通信:生产者消费者模式

    大家伙周末愉快,小乐又来给大家献上技术大餐.上次是说到了Java多线程的创建和状态|乐字节,接下来,我们再来接着说Java多线程-同步:synchronized 和线程通信:生产者消费者模式. 一.同 ...

  9. 从火箭发场景来学习Java多线程并发闭锁对象

    从火箭发场景来学习Java多线程并发闭锁对象 倒计时器场景 在我们开发过程中,有时候会使用到倒计时计数器.最简单的是:int size = 5; 执行后,size—这种方式来实现.但是在多线程并发的情 ...

随机推荐

  1. 【POJ】4007.Flood-it!

    原题戳这里 题解 搜索是个好东西,不是人人都会搜 迭代加深,然后用一个函数估值,值是除了和左上连通的部分还有几个颜色不同的块,如果走的步数加上估值大于当前枚举的深度就跳出 代码 #include &l ...

  2. 第一个web程序(ServletRequest , ServletResponse)

    一.ServletRequest 1.获取参数的方法(四种) > String getParameter(String name): 根据请求参数的名字, 返回参数值. 若请求参数有多个值(例如 ...

  3. Android中Xposed框架篇-微信实现本地视频发布到朋友圈功能

    微信非常庞大,还好有一些强大的工具,下面就来总结收获的知识. 一.使用adb shell dumpsys activity top命令快速定位页面 二.使用Jadx进行方法跟踪时候如果发现没有结果,可 ...

  4. 2017-2018-1 20179202《Linux内核原理与分析》第十一周作业

    Metasploit实现木马生成.捆绑.免杀 1.预备知识 (1)Metasploit Metasploit是一款开源的安全漏洞检测工具,全称叫做The Metasploit Framework,简称 ...

  5. 使用 Python 可以做什么?

    翻译自 <Python学习手册(第5版)> Systems Programming Python 对操作系统服务的内置接口使其非常适合编写可移植.可维护的系统管理工具和实用程序 utili ...

  6. Initializing the FallBack certificate failed . TDSSNIClient initialization failed

    安装SQL后服务不能启动,报错: 2014-03-24 14:33:10.06 spid13s     Error: 17190, Severity: 16, State: 1.2014-03-24 ...

  7. [leetcode DP]62.Unique Paths

    判断一个物体从左上角到右下角有多少种走法 class Solution(object): def uniquePaths(self, m, n): flag = [[1 for j in range( ...

  8. 常用的Jquery工具方法

    一.根据后端动态字段,如何把驻点输出在页面上?1.可以提前写好css,设置li的宽度,在页面中通过模板引擎语法动态加载不同的className.2.可以根据驻点个数和位置,用jquery去动态计算赋值 ...

  9. 支撑大规模公有云的Kubernetes改进与优化 (2)

    接下来我们按照kubernetes创建容器的详细过程,以及可能存在的问题. 一.API Server的认证,鉴权,Quota 当客户需要创建一个pod的时候,需要先请求API Server. Kube ...

  10. bzoj 2961

    根据“点在圆内”关系,列出点P(x0,y0)在圆C(x,y)内的关系: (x-x0)^2+(y-y0)^2 <= x^2+y^2 化简得: 2*x0*x+2*y0*y >= x0^2+y0 ...