用synchronized对方法进行同步,还真不一定线程安全,来看个简单的例子
上面的代码运行出来的结果:
看到没,并不是2000000,那么为什么f1和f3方法都用了synchronized关键字,然而并没有达到我们需要的结果呢?这需要从synchronized的原理开始讲起。
synchronized关键字有下面三种用法:
修饰实例方法:对当前实例加锁,进入方法需要获得当前实例的锁
修饰静态方法:对当前类对象加锁,进入静态方法需要获得当前类对象的锁
修饰代码块:对指定对象进行加锁,进入代码块需要获得指定对象的锁
那么上面三种方式有什么区别呢?这需要先理解下synchronized的底层语义。java中的同步是基于进入和退出管程(Moniter)对象来实现的,无论是显式同步(有明确的monitorenter和monitorexit指令,即同步代码块)还是隐式同步(同步方法,方法调用指令读取运行时常量池中的方法的ACC_SYNCHRONIZED标志来隐式实现的)。
先看下基于对象实现的,需要了解下java对象。在JVM中,对象在内存中的区域分成三部分:对象头,实例变量,填充数据。
实例变量:存放类的属性数据信息,包括父类的属性信息,如果是数组的实例部分还包括数组的长度,这部分内存按4字节对齐。
填充数据:由于虚拟机要求对象起始地址必须是8字节的整数倍。填充数据不是必须存在的,仅仅是为了字节对齐,这点了解即可。
对象头:是实现synchronized锁对象的基础。synchronized使用的锁对象是存储在Java对象头里的,其主要结构是由Mark Word 和 Class Metadata Address 组成。
其中Mark Word在默认情况下存储着对象的HashCode、分代年龄、锁标记位等以下是32位JVM的Mark Word默认存储结构
synchronized的对象锁,锁标识位为10,其中指针指向的是monitor对象(也称为管程或监视器锁)的起始地址。每个对象都存在着一个 monitor 与之关联,对象与其 monitor 之间的关系有存在多种实现方式,如monitor可以与对象一起创建销毁或当线程试图获取对象锁时自动生成,但当一个 monitor 被某个线程持有后,它便处于锁定状态。
了解了对象头,我们就可以知道为什么上面的代码虽然都使用了synchronized修饰,但是还是有线程安全问题,因为静态方法和实例方法锁的对象是不一致的(Monitor不是同一个),所以导致最终没有达到预期效果。
相关推荐
Synchronized锁在Spring事务管理下,导致线程不安全。
Servlet 线程安全问题是指在使用 Servlet 编程时,如果不注意多线程安全性问题,可能会导致难以发现的错误。Servlet/JSP 技术由于其多线程运行而具有很高的执行效率,但这也意味着需要非常细致地考虑多线程的安全性...
3. 懒汉式(线程安全):在多线程环境中,使用`synchronized`保证实例化过程的线程安全,但可能导致性能下降。 ```java public class Singleton { private static Singleton INSTANCE; private Singleton() {} ...
4. 避免在多线程环境中直接使用HashMap:如果你确定不需要在多线程环境下共享HashMap,那么可以考虑局部变量的方式,只在单个线程中使用HashMap,这样就无需担心线程安全问题。 总结起来,理解HashMap的线程不安全...
在Java编程中,`synchronized`关键字是用来解决多线程环境下的线程安全问题的关键工具。线程安全意味着当多个线程访问同一段代码时,该代码能够正确地处理并发情况,不会出现数据不一致或者资源竞争的问题。本文将...
在Java编程中,多线程同步是一个至关...总的来说,`synchronized`关键字是Java多线程编程中实现同步的关键工具,它通过锁定对象或代码块来确保线程安全。理解和正确使用`synchronized`对于构建可靠的并发程序至关重要。
Servlet的线程安全问题主要出现在实例变量的使用上。例如,一个Servlet实例中的实例变量被多个线程共享,如果没有适当的同步控制,可能会导致数据不一致。在上述例子中,`ConcurrentTest`Servlet定义了一个实例变量`...
使用`synchronized`会引入一定的性能开销,因为它涉及到锁的获取和释放。因此,对于不需要严格同步的代码,应尽量避免使用`synchronized`,以提高程序的并发性能。 总之,`synchronized`关键字是Java中实现线程...
1.什么是线程安全性(what) 2.如何分辨一个类是否线程安全?(HOW) 3.为什么hashmap不安全 why 3.1 插入HashMap.put 3.1.1 HashMap 在扩容的时候 3.2 HashMap 在删除数据的时候 0.背景 经常会看到说HashMap是线程...
Java 非线程安全类变线程安全类 Java 中的非线程安全类是指有状态的类,即有属性的类,这些类在多线程...Java 中的非线程安全类可以通过使用 ThreadLocal 或 synchronized 关键字来实现线程安全,避免线程安全问题。
测试线程安全通常包括模拟并发环境,使用多线程进行测试,观察并分析可能产生的错误或不一致。通过编写并运行多线程测试用例,可以发现潜在的线程安全问题,然后针对性地进行修复。 总之,理解Java内存模型和掌握...
然而,多线程环境下的数据安全性问题也尤为突出,这时候就需要用到同步机制来保证线程安全。"synchronized"关键字就是Java中实现线程同步的关键工具,它用于控制对共享资源的访问,防止出现数据不一致的情况。 标题...
2. **线程执行顺序**:`synchronized`不仅可以保证线程安全,还可以影响线程的执行顺序。在Java中,线程的调度是不确定的,但`synchronized`可以确保在某个线程进入同步代码块并持有锁后,其他等待的线程会按照FIFO...
这些集合一旦创建就不能修改,因此天然线程安全。 示例代码: ```java import java.util.*; import java.util.concurrent.*; public class ThreadSafeCollections { public static void main(String[] args) { ...
测试可能包括对局部变量的读写操作,以及涉及到同步机制如synchronized关键字,volatile修饰符,或者是使用ThreadLocal等技术来确保线程安全。 在标签中,“局部变量”、“线程”、“安全”、“测试”和“源码”是...
设计线程安全的`Action`时,你需要确保所有的方法都具有适当的同步机制,如`synchronized`关键字,或者使用`java.util.concurrent`包中的工具,如`ExecutorService`、`Semaphore`等。 2. **`javax.swing....
本文通过实例展示了使用synchronized、wait()和notify()实现线程交互的方法,帮助用户在使用Java多线程的场景有效避免多线程带来的不安全问题。理解Java线程各状态之间的关系及其切换,能够帮助用户在使用Java多...
线程安全是指当多个线程访问同一块代码时,如果每个线程都能得到预期的结果,且不产生数据不一致或同步问题,那么这块代码就被称为线程安全的。Java中的线程安全问题通常表现为竞态条件、死锁、活锁和饥饿现象。 ##...
线程安全,使用synchronized关键字