并发编程的三大挑战之原子性及其解决方案

文章讨论了在多线程环境下,由于线程切换导致的原子性问题,如在`count++`操作中可能出现的非预期结果。为了解决这个问题,文章提出了三种策略:使用`synchronized`关键字、CAS(CompareandSwap)以及`ReentrantLock`。每种方法都确保了同一时间只有一个线程能执行特定操作,从而保证了原子性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

目录

一、原子性问题

1、带来原子性问题的原因

 2、如何解决线程切换带来的原子问题

2.1、使用synchronized关键字来保证

2.2、使用CAS来保证原子性

2.3、使用lock锁来保证


一、原子性问题

1、带来原子性问题的原因

线程切换是带来原子的根本原因,java的并发程序是基于多线程的,自然就会涉及到任务切换。而任务切换的时机是可以发生cpu的时间片结束时,由于目前我们使用的编程语言都是高级语言,一条高级语言往往是需要多条CPU指令完成的,例如count++,至少需要三条CPU指令。

  1. 指令1:首先需要把变量count从主内存中加载cpu的寄存器中
  2. 指令2:在寄存器中执行+1操作
  3. 指令3:将结果写入内存(缓存机制可能导致写入的是cpu的缓存而不是内存)

如下图所示,两个线程如果在执行count++的时候,过程如果发生了线程切换,会导致得不到预期的结果2,可能会出现意向不到结果,两个线程对count执行++操作后,在主内存中值为1. 

原子性的定义:原子性指一个操作是不可分割的,不可中断的,一个线程在执行时,另一个线程不会影响到他

private static int count;

	public static void increment(){
		try {
			Thread.sleep(10);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		count++;
	}

	public static void main(String[] args) throws InterruptedException {
		Thread t1 = new Thread(() -> {
			for (int i = 0; i < 100; i++) {
				increment();
			}
		});
		Thread t2 = new Thread(() -> {
			for (int i = 0; i < 100; i++) {
				increment();
			}
		});
		t1.start();
		t2.start();
		t1.join();
		t2.join();
		System.out.println(count);
	}

 2、如何解决线程切换带来的原子问题

本质就是保存这块有非原子的操作语句,同一个时刻只能被一个线程访问到,并且对修改后的值,保证后续线程可见。通常的做法有:

2.1、使用synchronized关键字来保证

之前的increment()方法修改为如下方式:

	public static synchronized void increment(){
		try {
			Thread.sleep(10);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		count++;
	}

2.2、使用CAS来保证原子性

使用CAS来解决的时候,如下所示:

	private static AtomicInteger atomicInteger = new AtomicInteger();

	public static void increment(){
		try {
			Thread.sleep(10);
		} catch (InterruptedException e) {
			e.printStackTrace();
		}
		atomicInteger.incrementAndGet();
	}

2.3、使用lock锁来保证

当我们使用锁来保证原子问题时,其示例代码如下:

private static int count = 0;

	public static  void increment(){
		ReentrantLock  reentrantLock = new ReentrantLock();
		
		try {
			reentrantLock.lock();
			Thread.sleep(10);
			count++;
		} catch (InterruptedException e) {
			e.printStackTrace();
		}finally {
			reentrantLock.unlock();
		}
	}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值