今天在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. mysql执行带外键的sql文件时出现mysql ERROR 1215 (HY000): Cannot add foreign key constraint的解决

    ERROR 1215 (HY000): Cannot add foreign key constraint 最近在建表时遇到了这个错误,然后找了下找到了解决办法,记录下: 本来是要建两张表: 1 2 ...

  2. 关于DLNA

    Version:0.9 StartHTML:-1 EndHTML:-1 StartFragment:00000099 EndFragment:00005587  概念 DLNA的全称是DIGITAL ...

  3. fsck 工具 ——检查 与修复 Linux系统上的文件系统

    可能由于昨天关电脑断电源的问题, 后来开机,直接出现如下界面: 心里想,不会吧,电脑怎么又出问题了吧(上周的时候,手贱,把装系统的硬盘分区设为了非活动分区,电脑就启动不来了,后来手动引导起来的:): ...

  4. git 在命令行与图形状态下使用详情

    http://blog.csdn.net/risky78125/article/details/50850545 http://blog.csdn.net/risky78125/article/det ...

  5. (原)使用android studio ndk开发流程

    先使用android stuido创建一个app工程,创建工程的时候,.gradle目录结构下为2.8目录.(note:2.10目录为后续更新结果出现.) 依次修改上述红色方框标注部分内容: 1)修改 ...

  6. mysql的字符串函数

    From: http://www.cnblogs.com/xiaochaohuashengmi/archive/2010/12/13/1904330.html 对于针对字符串位置的操作,第一个位置被标 ...

  7. C#实现http协议支持上传下载文件的GET、POST请求

    C#实现http协议支持上传下载文件的GET.POST请求using System; using System.Collections.Generic; using System.Text; usin ...

  8. Asp.net中文本框全选的实现

    一.鼠标滑过textbox全选 前台: <asp:TextBox runat="server" onMouseOver="this.focus();this.sel ...

  9. 一款基于 Android 开发的离线版的 MM 图片浏览 App

    一款离线版的 MM 图片浏览 App,有点类似掌上百度的图片专栏应用.图片采用瀑布流展示方式,点击图片集,支持左右手势滑动切换图片:支持放大缩小功能. 实现功能:1)图片完全离线,不耗个人 GPRS ...

  10. VIM复制粘贴大全[转]

    用vim这么久 了,始终也不知道怎么在vim中使用系统粘贴板,通常要在网上复制一段代码都是先gedit打开文件,中键粘贴后关闭,然后再用vim打开编辑,真的不 爽:上次论坛上有人问到了怎么在vim中使 ...