并发程序的宏观性问题

主要有三个问题:
安全性问题,活跃性问题,性能问题。

首先安全性问题,表现是怎么样的呢?我们写并发程序时,希望程序按照我们期望的执行顺序来执行,但是他们都没按照我们期望的方式运行,那么怎样才能写出线程安全的程序呢?先来讨论一下引起并发程序bug的三个源头:
原子性,可见性,和有序性。

适用于一条规则就是,存在共享数据并且该数据会发生变化,有多个线程会同时读写一个数据。那面对需要多个线程共享的数据的情况下,怎么保证安全性呢?

于是引入了一个数据竞争的概念。即多个线程同时读写同一数据的情况,会产生数据竞争。可能通常情况下,认为通过加锁就能解决并发问题,其实这是片面的。

数据竞争的名字叫竞态条件,指的是程序的执行结果依赖线程执行的顺序。

demo:

class Account {
  private int balance;
  // 转账
  void transfer(
      Account target, int amt){
    if (this.balance > amt) {
      this.balance -= amt;
      target.balance += amt;
    }
  } 
}

当2个线程同时执行transfer方法时,并发进入,同时判断if条件,2个线程同时满足条件,就会发现各自线程当前都读取了this.balance于是都会执行下列转账操作,于是导致错误。
这类竞态条件的一种通用形式类似:

if (状态变量 满足 执行条件) {
  执行操作
}

再来一个demo:

public class Test {
  private long count = 0;
  synchronized long get(){
    return count;
  }
  synchronized void set(long v){
    count = v;
  } 
  void add10K() {
    int idx = 0;
    while(idx++ < 10000) {
      set(get()+1)      
    }
  }
}

给get,set方法加上 synchronized关键字,保证串行化。当2个线程同时执行add10K方法时,进入到get()+1.虽然set.get方法保证了串行化,但是2个线程分别得到了同一个get()+1值的可能性还是有的。于是满足了这样其中一个线程执行了一次set方法后,第二个线程再执行set方法就会把第一个线程的值给覆盖掉。
怎么解决这个方法呢,继续加锁,只不过锁的范围控制好竞态条件即可。

活跃性问题。指某个操作无法执行下去,常见的死锁就是一种典型的活跃性问题,除了死锁外,分别是活锁和饥饿。

活锁:有时线程虽然没有发生阻塞,但仍然会存在执行不下去的情况,这就是所谓的活锁。
即线程双方主动放弃资源后,最后同时竞争,还是同时阻塞。
解决办法:设置等待一个随机的时间,来降低发生竞争的概率。

饥饿:指的是线程因无法访问所需资源而无法执行下去的情况。
如果线程优先级“不均”,在 CPU 繁忙的情况下,优先级低的线程得到执行的机会很小,就可能发生线程“饥饿”;持有锁的线程,如果执行的时间过长,也可能导致“饥饿”问题。
解决饥饿方法:
一保证资源充足,二公平的分配资源,三就是避免长时间持有锁的线程的执行。三个方案中,方案一和方案三适用场景比较有限。那怎么实现方案二呢,使用Java里的公平锁即可。

性能问题:
使用锁,除了小心安全性,和活跃性,还要注意使用锁带来的性能开销。如果锁的范围过大,那么就会带来性能不佳。假设串行百分比是 5%,使用多核多线程能提升多少性能呢?20倍。阿姆达尔(Amdahl)定律告诉我们。

那么解决办法是什么:
一使用锁带来性能问题,那么就使用无锁的算法和数据结构,线程本地存储 (Thread Local Storage, TLS)、写入时复制 (Copy-on-write)、乐观锁等;Java 并发包里面的原子类也是一种无锁的数据结构;Disruptor 则是一个无锁的内存队列,性能都非常好……

二减少锁持有的时间,互斥锁本质上是将并行的程序串行化,增加性能,减少锁的执行时间,那么其它线程就会拥有更多的执行的机会,实现的技术例如使用细粒度的锁,一个典型的例子就是 Java 并发包里的 ConcurrentHashMap,它使用了所谓分段锁的技术(这个技术后面我们会详细介绍);还可以使用读写锁,也就是读是无锁的,只有写的时候才会互斥。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
本火锅店点餐系统采用Java语言和Vue技术,框架采用SSM,搭配Mysql数据库,运行在Idea里,采用小程序模式。本火锅店点餐系统提供管理员、用户两种角色的服务。总的功能包括菜品的查询、菜品的购买、餐桌预定和订单管理。本系统可以帮助管理员更新菜品信息和管理订单信息,帮助用户实现在线的点餐方式,并可以实现餐桌预定。本系统采用成熟技术开发可以完成点餐管理的相关工作。 本系统的功能围绕用户、管理员两种权限设计。根据不同权限的不同需求设计出更符合用户要求的功能。本系统中管理员主要负责审核管理用户,发布分享新的菜品,审核用户的订餐信息和餐桌预定信息等,用户可以对需要的菜品进行购买、预定餐桌等。用户可以管理个人资料、查询菜品、在线点餐和预定餐桌、管理订单等,用户的个人资料是由管理员添加用户资料时产生,用户的订单内容由用户在购买菜品时产生,用户预定信息由用户在预定餐桌操作时产生。 本系统的功能设计为管理员、用户两部分。管理员为菜品管理、菜品分类管理、用户管理、订单管理等,用户的功能为查询菜品,在线点餐、预定餐桌、管理个人信息等。 管理员负责用户信息的删除和管理,用户的姓名和手机号都可以由管理员在此功能里看到。管理员可以对菜品的信息进行管理、审核。本功能可以实现菜品的定时更新和审核管理。本功能包括查询餐桌,也可以发布新的餐桌信息。管理员可以查询已预定的餐桌,并进行审核。管理员可以管理公告和系统的轮播图,可以安排活动。管理员可以对个人的资料进行修改和管理,管理员还可以在本功能里修改密码。管理员可以查询用户的订单,并完成菜品的安排。 当用户登录进系统后可以修改自己的资料,可以使自己信息的保持正确。还可以修改密码。用户可以浏览所有的菜品,可以查看详细的菜品内容,也可以进行菜品的点餐。在本功能里用户可以进行点餐。用户可以浏览没有预定出去的餐桌,选择合适的餐桌可以进行预定。用户可以管理购物车里的菜品。用户可以管理自己的订单,在订单管理界面里也可以进行查询操作。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值