今天在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. Git安装遇到的问题fatal: Could not read from remote repository.的解决办法

    转自:https://blog.csdn.net/huahua78/article/details/52330792 查看远端地址 git remote –v 查看配置 git config --li ...

  2. Linux 常用小命令

    1.  查看目录的总和 du -sh 路径 2. 查看linux目录下所有某种类型的文件的行数--> 就是想看自己写了多少行代码 find /opt/code/zk_css -name '*.p ...

  3. WFA 认证 启动 sigma_dut方法

    WFA认证需要启动sigma_dut,记录记录一下启动过程. Android O平台命令如下 adb shell svc wifi disable adb shell rmmod wlan adb s ...

  4. Linux C语言连接 sqlserver数据库

    记录一下Linux下使用C语言连接sqlserver的方法. 连接前需要安装freetds. 参考: http://www.cnblogs.com/helloworldtoyou/p/6910075. ...

  5. mysql存储过程----临时表 temporary

    在存储过程中可以使用临时表,下面有一个分割字符串的例子 语法 1.创建:create temporary table 表名(列信息); 2.删除:drop table 表名; 3.清空:truncat ...

  6. Couchbase 集群小实践

    局域网 两台机  192.168.1.2  我们称为A机器   192.168.1.3   我们称为B机器   配置集群的时候,从A或者是B的web后台都可以添加, 在这里 我们以 A机器为主   目 ...

  7. Python内部机制。

    type ,object ,__class__ ,__bases__ ,__metaclass__ , -------------------------不明白的地方----------------- ...

  8. 【苏勇老师Linux 入门笔记】网络基础

    IP 地址 IP 编制时一个双层编制方案,一个 IP 地址标示一个主机 (或一个网卡接口). 一个 IP 地址分为两个部分:网络部分(所属区域)和主机部分(标示区域中的哪个主机).IPv4 共32位, ...

  9. 7款HTML5精美应用教程 让你立即爱上HTML5

    你喜欢HTML5吗?我想下面的这7个HTML5应用一定会让你爱上HTML5的,不信就一起来看看吧. 1.HTML5/jQuery雷达动画图表 图表配置十分简单 之前我们介绍过不少形形色色的HTML5图 ...

  10. win用VNC远程Ubuntu教程

    转载:https://blog.csdn.net/jiangchao3392/article/details/73251175 1.安装Xrdp Windows远程桌面使用的是RDP协议,所以ubun ...