线程安全

核心概念

原子性

原子性是指不可再分的最小操作指令,即单条机器指令,原子性操作任意时刻只能有一个线程,因此是线程安全的。
Java内存模型中通过readloadassignusestorewrite这6个操作保证变量的原子性操作。
这一点,跟数据库事务的原子性概念差不多,即一个操作(有可能包含有多个子操作)要么全部执行(生效),要么全部都不执行(都不生效)。 就是原子性说一个操作不可以被中途CPU暂停然后调度, 即不能被中断, 要不就执行完, 要不就不执行。
一个不正确的知识:“原子操作不需要进行同步控制”。

原子操作

是不能被线程调度机制中断的操作,一旦操作开始,那么它一定可以在可能发生中断之前执行完毕。
原子性可以应用于基本数据类型(除了longdouble),对于写入和读取,可以把它们当作原子操作来操作内存。但是,longdouble这两个64位长度的数据类型Java虚拟机并没有强制规定他们的readloadstorewrite操作的原子性,即所谓的非原子性协定,但是目前的各种商业Java虚拟机都把longdouble数据类型的4中非原子性协定操作实现为原子性。所以Java中基本数据类型的访问读写是原子性操作。
对于大范围的原子性保证需要通过lockunlock操作以及synchronized同步块来保证。

例子

比如A和B同时向C转账10万元。如果转账操作不具有原子性,A在向C转账时,读取了C的余额为20万,然后加上转账的10万,计算出此时应该有30万,但还未来及将30万写回C的账户,此时B的转账请求过来了,B发现C的余额为20万,然后将其加10万并写回。然后A的转账操作技术——将30万写回C的余额。这种情况下C的最终余额为30万,而非预期的40万。

上下文切换和线程池

上下文分类

上下文切换是指CPU的控制权由运行任务转移到另外一个就绪任务时所发生的事件。

  • 高并发,低耗时的情况,上下文切换本来就多,并且高并发就意味着CPU是处于繁忙状态的, 增加更多地线程也不会让线程得到执行时间片, 反而会增加线程切换的开销。
  • 低并发,高耗时,保证有空闲线程或者增加线程数目,接收新任务,可以减少线程切换。

    让步式上下文切换

    指执行线程主动释放CPU,与锁竞争严重程度成正比(锁竞争严重,释放多),可通过减少锁竞争来避免。

    抢占式上下文切换

    后者是指线程因分配的时间片用尽而被迫放弃CPU或者被其他优先级更高的线程所抢占,一般由于线程数大于CPU可用核心数引起,可通过调整线程数,适当减少线程数来避免。

    线程池

    关键点

  • 尽量减少线程切换和管理的开支:要求线程数尽量少,这样可以减少线程切换和管理的开支。
  • 最大化利用CPU:要求尽量多的线程,以保证CPU资源最大化的利用。

QPS,PV,RT线程之间的关系

QPS是什么

单个进程每秒请求服务器的成功次数
QPS = req/sec = 请求数/秒

QPS如何统计

QPS统计方式 [一般使用 http_load 进行统计]
QPS = 总请求数 / ( 进程总数 * 请求时间 )

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×