【JAVA多线程05】共享模型之无锁

无锁实例

在一些数量的增加和删除可以使用AtomicInteger来实现原子操作

package cn.itcast;
import java.util.ArrayList;
import java.util.List;

class xxx implements{
 @Override
 public void withdraw(Integer amount) {
 while (true) {
 int prev = balance.get();
 int next = prev - amount;
 if (balance.compareAndSet(prev, next)) {
 break;
 }
 }
 // 可以简化为下面的方法
 // balance.addAndGet(-1 * amount);
 }
}

interface Account {
 // 获取余额
 Integer getBalance();
 // 取款
 void withdraw(Integer amount);
 /**
 * 方法内会启动 1000 个线程,每个线程做 -10 元 的操作
 * 如果初始余额为 10000 那么正确的结果应当是 0
 */
 static void demo(Account account) {
 List<Thread> ts = new ArrayList<>();
 long start = System.nanoTime();
 for (int i = 0; i < 1000; i++) {
 ts.add(new Thread(() -> {
 account.withdraw(10);
 }));
 }
 ts.forEach(Thread::start);
 ts.forEach(t -> {
 try {
 t.join();
 } catch (InterruptedException e) {
 e.printStackTrace();
 }
 });
 long end = System.nanoTime();
 System.out.println(account.getBalance() 
 + " cost: " + (end-start)/1000_000 + " ms");
 }
}

CAS与volatile 

前面可以看到AtomicInteger的解决方法,内部并没有加锁,但是也可以保护共享变量的线程安全。CAS就是compareAndSet,他必须是原子操作的

他的执行原理是,比较初始值和共享变量的值,如果修改之前是一直则就确认赋值变量,否则失败 

CAS必须借助volatile才能读取到共享变量的最新值实现,比较并交换的效果。

为什么无锁的效率高

无锁的情况下,即使重试失败,线程始终在高速运行,没有停歇,而加了synchronized会让线程在没有锁的时候阻塞,发生上下文切换,上下文切换代价是挺高的。

但是在无锁的状态下,因为线程需要保持运行,需要额外CPU支持,虽然不会出现阻塞的情况,但是会分不到时间片,导致一样的上下文切换 。

CAS的特点

结合CAS和volatile可以实现无锁并发,适用于线程数较少,多核CPU的场景下

原子引用类型

主线程仅仅只能判断共享变量的值前后有没有发生变化,但是变化过程中是否经历了变化又变化回来是没有感知的,如果需要感知这一变化,需要加一个版本号

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值