今天在iteye上提了一个关于++操作和线程安全的问题,一位朋友的回答一言点醒梦中人,至此我对Java线程锁有了更加深刻的认识。在这里也做个总结供大家参考。

先看几段代码吧!

代码一:

  1. public class TestMultiThread2 implements Runnable{
  2. private static Object o = new Object();
  3. private static Integer si = 0;
  4. private static AtomicInteger flag = new AtomicInteger();
  5. @Override
  6. public void run() {
  7. for(int k=0;k<2000000;k++){
  8. synchronized(si){
  9. si++;
  10. }
  11. }
  12. flag.incrementAndGet();
  13. }
  14. public static void main(String[] args) throws InterruptedException{
  15. TestMultiThread2 t1 = new TestMultiThread2();
  16. TestMultiThread2 t2 = new TestMultiThread2();
  17. ExecutorService exec1 = Executors.newCachedThreadPool();
  18. ExecutorService exec2 = Executors.newCachedThreadPool();
  19. exec1.execute(t1);
  20. exec2.execute(t2);
  21. while(true){
  22. if(flag.intValue()==2){
  23. System.out.println("si>>>>>"+si);
  24. break;
  25. }
  26. Thread.sleep(50);
  27. }
  28. }
  29. }

为了方便看,重复的就不插入了,从代码二到代码四只插入run()方法中的代码,其他地方都一样

代码二:

  1. public void run() {
  2. for(int k=0;k<2000000;k++){
  3. synchronized(o){
  4. si++;
  5. }
  6. }
  7. flag.incrementAndGet();
  8. }

代码三:

  1. public void run() {
  2. for(int k=0;k<2000000;k++){
  3. synchronized(o){
  4. si++;
  5. o = new Object();
  6. }
  7. }
  8. flag.incrementAndGet();
  9. }

代码四:

  1. public void run() {
  2. for(int k=0;k<2000000;k++){
  3. synchronized(o){
  4. si++;
  5. Object temp = o;
  6. o = new Object();
  7. o = temp;
  8. }
  9. }
  10. flag.incrementAndGet();
  11. }

有了这四段代码我想问题大概可以说明白了,这里说一下输出吧。

代码一:<4000000

代码二:=4000000

代码三:<4000000

代码四:<4000000(PS:这个结果非常接近4000000)

这里说明一下我测试中碰到的问题,代码四一直没有跑出我想要的结果,主要是开始我设的循环次数太少,其实这里如果要这个现象更加明显一些可以在中间多new 几个Object 如下面的代码五,这样现象就比较明显了.

代码五:

  1. public void run() {
  2. for(int k=0;k<2000000;k++){
  3. synchronized(o){
  4. si++;
  5. Object temp = o;
  6. for(int m=0;m<10;m++){
  7. o = new Object();
  8. }
  9. o = temp;
  10. }
  11. }
  12. flag.incrementAndGet();
  13. }

为什么会出现上面的现象:

代码一:当si做++操作后(可以直接看字节码,这里不贴了),在putstatic之前有几步操作,就是我们常说的非原子操作,而这时候si已经不是原来的对象了,这样锁对另外一个线程来说就失效了,我想代码三和代码四就是最好的佐证,代码四更有说服力。当时因为没有出现预想的情况困惑了挺久。

其实这里用字节码来解释还不是很严谨,最好的当然直接是汇编代码

如有什么问题还希望各位读者指正。

zhuanzi:http://blog.csdn.net/luohuacanyue/article/details/8307617

[置顶] 深入探析Java线程锁机制的更多相关文章

  1. Java 线程锁机制 -Synchronized Lock 互斥锁 读写锁

    (1)synchronized 是互斥锁: (2)ReentrantLock 顾名思义 :可重入锁 (3)ReadWriteLock :读写锁 读写锁特点: a)多个读者可以同时进行读b)写者必须互斥 ...

  2. JAVA线程锁-读写锁

    JAVA线程锁,除Lock的传统锁,又有两种特殊锁,叫读写锁ReadWriteLock 其中多个读锁不互斥,读锁和写锁互斥,写锁和写锁互斥 例子: /** * java线程锁分为读写锁 ReadWri ...

  3. Java线程锁一个简单Lock

    /** * @author * * Lock 是java.util.concurrent.locks下提供的java线程锁,作用跟synchronized类似, * 单是比它更加面向对象,两个线程执行 ...

  4. Java线程锁&分布式锁的理解及应用

    了解Java线程锁之前,先理解线程和进程的定义.进程是操作系统分配资源(CPU)的基本单位,线程是CPU执行的基本单位,一个进程可拥有多个线程,同进程间的多个线程共享分配给进程的资源.比如启动JVM时 ...

  5. 工作常用4种Java线程锁的特点,性能比较、使用场景

    多线程的缘由 在出现了进程之后,操作系统的性能得到了大大的提升.虽然进程的出现解决了操作系统的并发问题,但是人们仍然不满足,人们逐渐对实时性有了要求. 使用多线程的理由之一是和进程相比,它是一种非常花 ...

  6. Java的锁机制--synchronsized关键字

    引言 高并发环境下,多线程可能需要同时访问一个资源,并交替执行非原子性的操作,很容易出现最终结果与期望值相违背的情况,或者直接引发程序错误. 举个简单示例,存在一个初始静态变量count=0,两个线程 ...

  7. Java线程锁,synchronized、wait、notify详解

    (原) JAVA多线程这一块有点绕,特别是对于锁,对锁机制理解不清的话,程序出现了问题也很难找到原因,在此记录一下线程的执行以及各种锁. 1.JAVA中,每个对象有且只有一把锁(lock),也叫监视器 ...

  8. lesson3:java的锁机制原理和分析

    jdk1.5之前,我们对代码加锁(实际是对象加锁),都是采用Synchronized关键字来处理,jdk1.5及以后的版本中,并发编程大师Doug Lea在concurrrent包中提供了Lock机制 ...

  9. java的锁机制

    一段synchronized的代码被一个线程执行之前,他要先拿到执行这段代码的权限,在Java里边就是拿到某个同步对象的锁(一个对象只有一把锁): 如果这个时候同步对象的锁被其他线程拿走了,他(这个线 ...

随机推荐

  1. C语言中二维字符数组的定义和初始化

    本篇日志关于二维字符数组的定义和初始化.我相信这篇文章属于菜鸟级的,高手请直接无视. 一般来说,我们可能会希望定义一个二维字符数组并且在定义的时候就用一些字符串来初始化它.比如说: ][MAX_LEN ...

  2. dd 命令 sd卡系统迁移

    Linux系统如果想做备份还原,使用ghost的时候经常出现问题,后来发现可以直接使用dd命令完成硬盘的克隆和还原.当拷贝完硬盘后,就可以拿这个硬盘放到其它设备上跑了.也就是完成了“烧写”了. 实际操 ...

  3. Tensorflow不显示log

    import os os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'

  4. C语言简明数据类型指南

    一.常用的数据类型 char:字符在计算机的存储器中以字符编码的形式保存,字符编码是一个数字,因此在计算机看来,A与数字65完全一样(65是A的ASCII码). int:如果要保存一个整数,通常可以使 ...

  5. (转)Android 5.1.1 源码目录结构

    转自:http://blog.csdn.net/tfslovexizi/article/details/51888458最近公司培训新同事,我负责整理一点关于android的基础知识,遥想当年,刚接触 ...

  6. (转)OpenGL ES编程入门资源集合

     出自:http://blog.csdn.net/u013467442/article/details/44498125     OpenGL ES 2.0中文手册:http://www.dreami ...

  7. (转)simple-framework(MaliSDK框架分析)

     出自:http://blog.csdn.net/u013467442/article/details/46940501 simple-framework(Mali SDK框架分析) 1.所有的定义及 ...

  8. llinux 环境安装编译 nginx (源码安装包)

    简介: Nginx是一款轻量级的Web 服务器/反向代理服务器及电子邮件(IMAP/POP3)代理服务器,并在一个BSD-like 协议下发行.由俄罗斯的程序设计师Igor Sysoev所开发,供俄国 ...

  9. mybatis 参数为String,用_parameter 取值

    mybatis 参数为String,if test读取该参数代码: <select id="getMaxDepartId" parameterType="java. ...

  10. 定时任务quartz与spring的集成

    我想要在spring的集成框架中使用spring , 暂时采用quartz 根据下面的几篇博客实现了(懒得说了,直接丢链接): Quartz实现动态定时任务 Spring 3整合Quartz 2实现定 ...