`
gao_xianglong
  • 浏览: 467058 次
  • 性别: Icon_minigender_1
  • 来自: 深圳
社区版块
存档分类
最新评论

聊聊synchronized为什么无法锁住Integer

    博客分类:
  • Java
阅读更多

聊聊synchronized为什么无法锁住Integer

 

假设并发环境下,业务代码中存在一些统计操作,为了保证线程安全,开发人员往往会对计数值进行加锁(synchronized),值得注意的是,直接对Integer类型进行加锁,似乎并会达到预期效果,比如下面这段代码:

Integer num = new Integer(0);

public void test() throws InterruptedException {

final int THREAD_SIZE = 10;

final int TASK_SIZE = 100000;

final CountDownLatch latch = new CountDownLatch(THREAD_SIZE);

for (int i = 0; i < THREAD_SIZE; i++) {

new Thread() {

public void run() {

for (int j = 0; j < TASK_SIZE / THREAD_SIZE; j++) {

synchronized (num) {

num++;

}

}

latch.countDown();

}

}.start();

}

latch.await();

System.out.println("num-->" + num);

}

 

上述代码示例中,总共有10个线程运行,每个线程执行次数为10000(taskSize/threadSize),但是实际程序输出结果却并非是10W次,或许有些同学会觉得诧异,在对计数值numInteger)进行递增操作前,已经执行了加锁操作,为啥还是非线程安全。我们首先来看一下上述程序的线程堆栈信息:

 

 

上图中,每一个线程锁住的资源其实都并非是同一个,这就可以解释为什么Integer类型进行加锁仍然是非线程安全的

 

或许有同学会说,JavaAPI提供有线程安全的AtomicInteger为啥不用,尽管AtomicInteger是线程安全的,但是接下来我们还是要聊一聊为啥锁不住Integer等原始数据类型的封装类型。

 

JAVA5为原始数据类型提供了自动装/拆箱功能,假设对Integer进行递增/递减操作后,其实HashCode已经发生了变化,synchronized自然也不是同一个对象实例,Integer的源码,如下所示:

 

 

从源码中可以看出,当为Integer赋值数值在-128~127区间时,会从Integer中的一个Integer[]中获取一个缓存的Integer对象,而超出区间值得时候,每次都会new一个新的Integer对象,假设下述这段代码:

Integer num = new Integer(300);

System.out.println("identityHashCode-->" + System.identityHashCode(num));

System.out.println("hashCode-->" + num.hashCode());

num = 300;

System.out.println("identityHashCode-->" + System.identityHashCode(num));

System.out.println("hashCode-->" + num.hashCode());

 

实际程序输出为:

identityHashCode-->627248822

hashCode-->300

identityHashCode-->523481450

hashCode-->300

 

 

Synchronized锁的是对象,也就是identityHashCode所指向的内存地址中的对象实例(根据对象内存地址生成散列值),而hashcode输出的是值得散列值。所以为啥上述程序示例中,identityHashCode每次不同,而hashCode输出的值却相同。

 

最后总结下,synchronized(Integer)时,当值发生改变时,基本上每次锁住的都是不同的对象实例,想要保证线程安全,推荐使用AtomicInteger之类会更靠谱。

 

分享到:
评论

相关推荐

    简单聊聊Synchronized和ReentrantLock锁.docx

    当一个线程进入一个由synchronized修饰的方法或代码块时,其他线程将无法同时访问同一方法或代码块。Synchronized具有自动释放锁的特点,当线程执行完毕或遇到异常时,锁会自动释放,无需程序员显式调用解锁操作。...

    java锁机制Synchronizedjava锁机制Synchronized

    为什么使用 Synchronized 代码块 使用 Synchronized 代码块可以缩小同步的影响范围,提高程序的运行效率。同时,Synchronized 代码块也可以在一定时期内霸占某个对象的钥匙,避免其他线程访问该对象的上锁房间。 ...

    Java并发 synchronized锁住的内容解析

    Java并发synchronized锁住的内容解析 Java并发synchronized锁住的内容解析是Java并发编程中的一种重要机制,用于解决多线程并发访问同一个资源时可能出现的线程安全问题。通过使用synchronized关键字,可以锁住当前...

    Synchronized锁在Spring事务管理下线程不安全

    Synchronized锁在Spring事务管理下,导致线程不安全。

    synchronized枷锁实例

    本文将深入探讨`synchronized`关键字的用法,包括类锁、对象锁、方法锁以及它们之间的关系。 **类锁(Class Lock)** 类锁是通过类的Class对象实现的,当一个线程访问类的静态 synchronized 方法或同步代码块时,就...

    java 偏向锁、轻量级锁及重量级锁synchronized原理.docx

    2. **轻量级锁**:当偏向锁无法满足多线程并发时,会转变为轻量级锁。轻量级锁使用CAS(Compare and Swap,比较并交换)操作来尝试获取锁,如果成功,就继续执行;如果失败,说明已有其他线程持有锁,这时轻量级锁...

    java锁机制Synchronized.pdf

    java锁机制Synchronized.pdf

    解析Java编程之Synchronized锁住的对象

    Java synchronized锁住的对象解析 在Java编程中,synchronized关键字是用于同步的关键字,它可以用于锁住一个对象,以实现线程同步。但是,在使用synchronized关键字时,需要了解锁住的到底是哪个对象,否则可能...

    lock锁,lock锁和synchronized的对比

    lock锁,lock锁和synchronized的对比 # Lock锁 JDK5.0后Java提供了一种更加强大的线程同步机制。一种显式定义同步锁对象来实现锁,提供了对共享资源的独占访问,每次只能有一个线程对Lock对象加锁,线程开始访问...

    透彻理解Java中Synchronized(对象锁)和Static Synchronized(类锁)的区别

    Java 中 Synchronized(对象锁)和 Static Synchronized(类锁)的区别 Synchronized 和 Static Synchronized 是 Java 中两种同步机制,它们都用于解决多线程并发访问的安全问题。然而,它们之间存在着本质的区别。...

    正确使用多线程同步锁@synchronized()1

    在Objective-C中,当你使用`@synchronized`块包围一段代码时,会为指定的对象创建一个互斥锁。如果当前线程已经持有了该锁,那么它可以再次获取并执行内部的代码,而不会造成死锁。这种特性使得在嵌套使用`@...

    28.线程的同步机制-synchronized同步语句-synchronized(this)代码块是锁定当前对象.mp4

    在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。

    21.线程的同步机制-synchronized同步方法-锁自动释放.mp4

    在学习Java过程中,自己收集了很多的Java的学习资料,分享给大家,有需要的欢迎下载,希望对大家有用,一起学习,一起进步。

    Synchronized_锁升级知识点总结

    但如果自旋超过了预定次数,或者锁竞争激烈,线程可能无法在短时间内获得锁,此时轻量级锁会升级为重量级锁。 重量级锁是阻塞锁的一种,在获取锁失败后,线程会被阻塞挂起,直到锁被释放,其他线程才有机会获得锁。...

    实例解析Java中的synchronized关键字与线程平安问题_.docx

    synchronized() 中是锁住的对象,synchronized(this) 锁住的只是对象本身,同一个类的不同对象调用这个方法并不会被锁住,而 synchronized(className.class) 实现了全局锁的功能,全部这个类的对象调用这个方法都受...

    synchronized锁自旋.docx

    《深入理解synchronized锁自旋机制》 在Java并发编程中,`synchronized`关键字扮演着重要的角色,它提供了一种线程同步机制,确保共享资源在同一时刻只能被一个线程访问。本文将深入探讨`synchronized`锁的内部机制...

    java里面synchronized用法.doc

    在上面的例子中,MySubClass 中的 myMethod 方法不自动变成 synchronized 方法,需要显式地指定它为 synchronized 方法。 四、synchronized 关键字的使用示例 以下是一个简单的示例代码,演示了 synchronized ...

    Java synchronized使用案例

    4. **锁膨胀**:如果同步代码块的性能瓶颈导致CPU开销过大,JVM会将轻量级锁升级为重量级锁(监视器锁),这可能导致性能下降。 四、`synchronized`与其他并发工具类的对比 1. **ReentrantLock**:具有`...

    java中synchronized用法

    Synchronized 关键字的作用是取得对象的锁,而不是把一段代码或函数当作锁。每个对象只有一个锁与之相关联。实现同步是要很大的系统开销作为代价的,甚至可能造成死锁,所以尽量避免无谓的同步控制。 当 ...

    java 多线程synchronized互斥锁demo

    标题中的"java 多线程synchronized互斥锁demo"指的是一个示例,展示了如何在多线程环境下使用`synchronized`关键字创建互斥锁,确保同一时间只有一个线程可以访问特定的代码块或方法。 描述中的"一个多线程访问的同...

Global site tag (gtag.js) - Google Analytics