多线程 基本类型的原子性问题

本文探讨了Java语言规范中定义的一些原子操作,例如char和int类型的赋值与引用操作,并解释了为什么long和double类型的赋值操作并非总是原子的。文章还提供了解决方案,包括使用synchronized关键字和volatile关键字来确保操作的原子性。

在java的语言规格中,一开始就定义了一些原子的操作,如,char ,int 这些的赋值与引用是原子的,

例如,两个线程同时对int类型的字段n进行赋值,一个使n=123 ,一个线程使n=345.

那么最后n的值不是123就是345,而不用担心模式会混合在一起。

但long与double的指定,引用操作并不是不可分割的

如对于long类型的a 赋值 ,两个线程分别使其a = 1234L ,a = 5678L

结果可能为,1234L,也可能为5678L,也可能为12345678L,也可能0L,等其他的方式。

解决方法,

1、加synchronized内操作。

2、在前面加上volatile关键字,则这些字段的操作就会成为不可分割的了

### Java 多线程中的原子性问题及其解决方案 #### 1. 原子性的定义 在多线程环境中,原子操作是指不可中断的操作。如果某个操作被多个线程同时访问,则该操作要么完全执行完成,要么根本不执行[^1]。当一个操作不是原子操作时,就可能出现线程安全问题。 #### 2. 非原子性引发的问题 假设存在一个计数器变量 `trainCount` 被多个线程共享并对其进行增减操作。由于读取、判断和写入可能不是一个整体的原子操作,因此可能导致数据竞争条件(Race Condition),从而破坏程序的一致性和正确性[^3]。 #### 3. 使用同步代码块解决原子性问题 通过使用 `synchronized` 关键字包裹可能发生冲突的代码区域,可以确保同一时刻只有一个线程进入临界区,进而保证操作的原子性。以下是基于售票系统的例子: ```java public class TicketSale { private int trainCount = 100; private final Object object = new Object(); public void sale() { synchronized (object) { // 同步代码块 if (trainCount > 0) { System.out.println(Thread.currentThread().getName() + ", 出售第" + (100 - trainCount + 1) + "张票"); trainCount--; } } } } ``` 上述代码中,`synchronized(object)` 确保每次只有一个线程能够修改 `trainCount` 的值,防止其他线程干扰当前线程的操作[^2]。 #### 4. 利用锁机制实现更细粒度的控制 除了基本的同步代码块外,Java 提供了更高层次的锁机制——ReentrantLock 类型锁。它允许显式获取和释放锁,并支持超时等待等功能。下面是一个简单的 ReentrantLock 示例: ```java import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; public class CounterWithLock { private int count = 0; private Lock lock = new ReentrantLock(); public void increment() { lock.lock(); // 获取锁 try { count++; } finally { lock.unlock(); // 无论是否异常都需解锁 } } public int getCount() { return count; } } ``` 这里展示了如何利用 `ReentrantLock` 来替代传统的 `synchronized` 方法或语句块,提供更加灵活的锁定策略。 #### 5. 使用原子简化开发过程 对于某些特定场景下频繁使用的简单类型(如整数加减运算),可以直接采用 JDK 中内置的 Atomic 包下的工具代替手动管理锁的方式提高效率。例如 AtomicInteger 就非常适合处理似的计数值更新需求: ```java import java.util.concurrent.atomic.AtomicInteger; public class SafeCounter { private AtomicInteger counter = new AtomicInteger(0); public void addOne() { while(true){ int currentVal = counter.get(); boolean successfulUpdate = counter.compareAndSet(currentVal, currentVal+1); if(successfulUpdate){ break; } } } public int get(){ return counter.get(); } } ``` 这段代码演示了无锁算法的思想,即借助 CAS(compare-and-swap) 操作达成高效且低开销的数据一致性维护目标。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值