今天在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. 自然语言交流系统 phxnet团队 创新实训 个人博客 (五)

    有关我们这个项目:智能自然语言交流系统,所借鉴的技术有: 第一:我们使用了科大讯飞的在线语音转换,涉及的有文本传给云端服务器的文字转换成语音和本地的语音上传给服务器转换成文字. 涉及的相关的代码有: ...

  2. thinkphp中memcache的用法实例

    本文实例讲述了thinkphp中memcache的用法.分享给大家供大家参考.具体分析如下: 1.下载并安装memcache ① window下安装memcache. 下载memcached.exe ...

  3. sqlldr 学习总结1

    1.建表语法(采用scott中的emp表) create table emp(  empno    number(4) not null,  ename    varchar2(10),  job   ...

  4. form表单target的用法

    偶然有一机会发现form表单的target的用法,可以实现当前页表单提交而不进行跳转刷新.代码如下,首页在页面里准备一form表单和一iframe <form action="提交的a ...

  5. 第三百三十三节,web爬虫讲解2—Scrapy框架爬虫—Scrapy模拟浏览器登录—获取Scrapy框架Cookies

    第三百三十三节,web爬虫讲解2—Scrapy框架爬虫—Scrapy模拟浏览器登录 模拟浏览器登录 start_requests()方法,可以返回一个请求给爬虫的起始网站,这个返回的请求相当于star ...

  6. Java如何停止线程?

    在Java编程中,如何停止线程? 以下示例演示了如何通过创建一个用户定义的方法run()方法和Timer类来停止线程. package com.yiibai; import java.util.Tim ...

  7. e830. 向JTabbedPane中加入一个卡片

    This example demonstrates various ways to add a tab to a tabbed pane. // Create a tabbed pane JTabbe ...

  8. B/S模式实现批量打包apk

    界面流程 界面例如以下: 这是一个使用html编写的界面,界面分为两半.两个frame.左边为操作栏,右边为控制台输出. 打包流程: 选择须要打包的渠道后,点击打包,等待server打包,并把日志输出 ...

  9. c# 创建压缩包并下载文件

    //DLL using ICSharpCode.SharpZipLib.Core;using ICSharpCode.SharpZipLib.Zip; public void DownloadZipF ...

  10. CentOS7修改设置静态IP和DNS

    当前位置: 主页 > CentOS入门 > 系统配置 > CentOS7修改设置静态IP和DNS 时间:2016-02-22 00:55来源:blog.csdn.net 作者:get ...