Java线程有两个特性,可见性和有序性。多个线程之间是不能直接传递数据交互的,它们之间的交互只能通过共享变量来实现。
可见性:当一个对象在多个内存中都存在副本时,如果一个内存修改了共享变量,其它线程也应该能够看到被修改后的值。拿上篇博文中的例子来说明,在多个线程之间共享了PrintString类的一个对象,这个对象是被创建在主内存(堆内存)中,每个线程都有自己的工作内存(线程栈),工作内存存储了主内存PrintString对象的一个副本,当线程操作PrintString对象时,首先从主内存复制PrintString对象到工作内存中,然后执行代码printer.print(),改变了builder值,最后用工作内存PrintString刷新主内存PrintString。因此上篇博文的例子没有保证可见性。
有序性:多个线程执行时,CPU对线程的调度是随机的,我们不知道当前程序被执行到哪步就切换到了下一个线程,一个最经典的例子就是银行汇款问题,一个银行账户存 款100,这时一个人从该账户取10元,同时另一个人向该账户汇10元,那么余额应该还是100。那么此时可能发生这种情况,A线程负责取款,B线程负责 汇款,A从主内存读到100,B从主内存读到100,A执行减10操作,并将数据刷新到主内存,这时主内存数据100-10=90,而B内存执行加10操 作,并将数据刷新到主内存,最后主内存数据100+10=110,显然这是一个严重的问题,我们要保证A线程和B线程有序执行,先取款后汇款或者先汇款后取款。
为保证可见性和有序性,需要引入同步机制。JAVA关键字volatile和锁机制保证了线程间的同步。
volatile:一个变量可以被volatile修饰,在这种情况下内存模型(主内存和线程工作内存)确保所有线程可以看到一致的变量值。volatile变量具有可见性特性,但是不具备原子特性。这就是说线程能够自动发现 volatile 变量的最新值。Volatile 变量可用于提供线程安全,但是只能应用于非常有限的一组用例:多个变量之间或者某个变量的当前值与修改后值之间没有约束。因此,单独使用 volatile 还不足以实现计数器、互斥锁或任何具有与多个变量相关的不变式(Invariants)的类(例如 “start <=end”)。只能在有限的一些情形下使用 volatile 变量替代锁。要使 volatile 变量提供理想的线程安全,必须同时满足下面两个条件:
- 对变量的写操作不依赖于当前值。
- 该变量没有包含在具有其他变量的不变式中。
第一个条件的限制使 volatile 变量不能用作线程安全计数器。虽然增量操作(x++
)看上去类似一个单独操作,实际上它是一个由读取-修改-写入操作序列组成的组合操作,必须以原子方式执行,而 volatile 不能提供必须的原子特性。实现正确的操作需要使 x
的值在操作期间保持不变,而 volatile 变量无法实现这点。大多数编程情形都会与这两个条件的其中之一冲突,使得 volatile 变量不能像 synchronized
那样普遍适用于实现线程安全。
因此,虽然volatile变量可以提供优于锁的性能优势,但是不能保证线程安全,所以最好不要用volatile保证性能安全,除非您确实是一个编程高手。
锁的讲解见下篇。
相关推荐
不同的平台,内存模型是不一样的,但是jvm的内存模型规范是统一的。...JVM定义了自己的内存模型,屏蔽了底层平台内存管理细节,对于java开发人员,要清楚在jvm内存模型的基础上,如果解决多线程的可见性和有序性。
Java多线程编程中,原子性、可见性和有序性是三个关键的概念,它们确保了多线程环境下的正确性。 1. 原子性(Atomicity) 原子性指的是一个操作不可被中断,要么全部执行,要么完全不执行。在Java中,非原生类型的...
接着,文章讨论了Java多线程同步机制中可能出现的安全性问题,如可见性、有序性和互斥性问题,并提出了解决这些问题的方法,包括使用ThreadLocal和Lock对象。 在文章的后半部分,讨论了Java多线程执行过程的机制和...
"并发二:原子性、可见性、有序性" 本文主要讲解了Java内存模型(JMM)中关于...Java内存模型(JMM)中关于并发编程的三个基本概念:原子性、可见性和有序性,都是保障多线程编程中数据的一致性和结果正确性的基础。
不同的平台,内存模型是不一样的,但是jvm的内存模型规范是统一的。...JVM定义了自己的内存模型,屏蔽了底层平台内存管理细节,对于java开发人员,要清楚在jvm模型的基础上,如果解决多线程的可见性和有序性。
Java多线程编程中,可见性和有序性是两个至关重要的概念,它们直接影响到并发执行的正确性和线程安全。在Java内存模型(JMM)中,这些特性得到了明确的规定。 **可见性**指的是一个线程对共享变量的修改能够被其他...
- `volatile`关键字:用于标记共享变量,确保多线程环境下的可见性和有序性,但不保证原子性。 - `join()`方法:让当前线程等待另一个线程完成其执行。 4. **线程优先级与调度**:Java的`Thread`类提供了设置线程...
然而,并发编程也带来了一系列挑战,如线程安全、可见性、原子性和有序性问题。 **并发理论基础**: 并发编程的核心在于多线程,允许多个执行单元在同一时间执行任务,以充分利用系统资源。在Java中,通过创建...
- ** volatile 关键字**: 保证共享变量的可见性和有序性,防止指令重排序。 - **`wait()`, `notify()`和`notifyAll()`方法**: 用于线程间的通信,让线程等待或唤醒其他线程。 6. **线程组** 线程可以组织成线程...
10. **Java内存模型**:书中涉及Java内存模型(JMM),解释了线程之间的可见性和有序性,以及volatile关键字的作用。 11. **并发性能分析与调优**:如何监控和分析线程性能,以及如何优化多线程程序,提高系统效率...
- ** volatile关键字**:确保了多线程环境下的变量可见性和有序性,但不保证原子性。 - **锁机制**:包括内置锁( synchronized)、显式锁(java.util.concurrent.locks包下的Lock接口)及其相关类。 - **线程...
3. **线程安全**:理解volatile关键字的作用,它能确保多线程环境下的变量可见性和有序性。 4. **线程池**:ExecutorService和ThreadPoolExecutor是Java提供的线程池框架,它们可以有效管理和控制线程,提高系统...
2. volatile关键字:保证变量的可见性和有序性,但不保证原子性。 3. Lock接口与ReentrantLock类:提供了比synchronized更灵活的锁机制,支持公平锁、非公平锁、读写锁等。 4. volatile与synchronized的区别:...
volatile关键字则用于确保变量的可见性和有序性,防止指令重排序对多线程环境造成的影响。更高级的并发控制机制如Lock接口(ReentrantLock可重入锁、ReadWriteLock读写锁)提供了比synchronized更灵活的控制,比如...
`synchronized`关键字用于保证线程间的可见性和有序性。它可以修饰方法或者代码块,确保任何时候只有一个线程可以访问被锁定的对象或代码块。 ```java public synchronized void method() { // 此方法在同一时刻只...
2. **单例模式中的双重检查锁定**:在实现线程安全的单例模式时,`volatile`关键字可以用来保证实例创建过程中的可见性和有序性,避免多线程环境下可能出现的问题。 3. **懒汉式初始化**:在某些情况下,为了避免...
此外,Java还提供了volatile关键字,保证变量的可见性和有序性,防止线程之间的数据不一致。 Java的`java.util.concurrent`包提供了高级并发工具,如ExecutorService、Future、Semaphore(信号量)和CyclicBarrier...
总结来说,Java内存模型通过原子性、有序性和可见性保证了多线程环境下的数据一致性。理解并熟练运用这些概念是编写高效、线程安全的Java代码的基础。在实际开发中,应根据需求选择合适的方式来确保这三个特性,以...
9. **JVM与多线程**:理解JVM的内存模型(JMM)对于理解多线程至关重要,包括可见性和有序性等概念。 10. **性能调优**:如何根据实际需求调整线程数量,平衡CPU负载和系统响应时间,是优化多线程程序的关键。 11....
- **volatile 关键字**:用于标记可能被多个线程访问的变量,确保线程间的可见性和有序性。 - **synchronized 关键字**:用于实现对共享资源的互斥访问,防止多个线程同时修改同一个资源。 #### 七、线程安全问题 -...