多线程学习总结——线程安全性问题

一、竞态

定义:

  1. 状态变量:即类的实例变量、静态变量。

  2. 共享变量:即可以被多个多线程共同访问的变量。状态变量由于可以被多个线程共享,所以也被称之为共享变量。共享变量强调的是共享,不一定就会被多个线程共同访问。

竞态:当多个线程同时访问共享资源(如共享变量)时就会发生竞态。

 

发生竞态的两种模式:

read-modify-write(读-改-写):

    该操作一般分为这样几个步骤:读取一个共享变量的值(read),然后根据该值做一些计算(modify),接着更新共享变量的值(write)。

    例如:对一个共享变量i进行'++'的操作,①读取i的值到寄存器r1中i,②在寄存器r1的值进行+1操作,③将r1写入到i所在的内存空间。一个线程在执行完指令①之后到开始(或者正在)执行指令②的这段时间内其他线程可能已经更新了共享变量( i)的值,这就使得该线程在执行指令②时使用的是共享变量的旧值(读脏数据)。接着,该线程把根据这个旧值计算出来的结果更新到共享变量,而这又使得其他线程对该共享变量所做的更新被“覆盖”,即造成了更新丢失。

check-then-act(检测而后行动):

    该操作一般分为这样几个步骤:读取某个共享变量的值,根据该变量的值决定下一步的动作是什么。

    例如:①对一个共享变量sequence(Integer类型)进行判断,②如果大于10则重新赋值为0,否则就进行加1操作。一个线程在执行完子操作①到开始(或者正在)执行子操作②的这段时间内,其他线程可能已经更新了共享变量的值而使得语句中的条件变为不成立,那么此时该线程仍然会执行子操作②,尽管这个子操作所需的前提(if语句中的条件)实际上并未成立,可能导致丢失更新和读脏数据的问题。

 

二、线程安全性

    如果一个类如果在单线程下能过正常的运行,并且在多线程环境不做任何的改变的情况下也能正常的运行,我们就称这个类是线程安全的,即这个类用线程安全性。如果一个类时线程安全的,那么他就不会导致竞态;反之一个类能过导致竞态,那么就称之为非线程安全的。

    如果一个类不是线程安全的,那么它在多线程环境下就存在线程安全性问题。线程安全性问题主要表现为三个方面:原子性、可见性和有序性。

 

(一)原子性(Atomic):

    如果涉及对共享变量的访问的操作,若除了对操作该共享变量线程外的任意线程来看,这个操作是“不可分割的”,那么该操作就是原子操作,相应的我们就称这样的操作具有原子性。   

    理解原子操作这个概念还需要注意以下两点:

  1. 原子操作是针对访问共享变量的操作而言的。也就是说,仅涉及局部变量访问的操作无所谓是否是原子的,或者干脆把这一类操作都看成原子操作

  2. 原子操作是从该操作的执行线程以外的线程来描述的,也就是说它只有在多线程环境下有意义。换言之,单线程环境下一个操作无所谓是否具有原子性,或者我们干脆把这一类操作都看成原子操作。

    原子操作的“不可分割的”包含以下两层含义:

  1. 访问(读、写)某个共享变量的操作从其执行线程以外的任何线程来看,该操作要么已经执行结束要么尚未发生,即其他线程不会“看到”该操作执行了部分的中间效果。

  2. 访问同一组共享变量的原子操作是不能够被交错的(即在一个线程访问共享变量的时候,另一个线程无法访问该共享变量),这就排除了一个线程执行一个操作期间另外一个线程读取或者更新该操作所访问的共享变量而导致的干扰(读脏数据)和冲突(丢失更新)的可能。

    java有两种方式可以实现原子性:

  1. 锁(Lock):锁具有排他性,即锁具有排他性,即它能够保障一个共享变量在任意一个时刻只能够被一个线程访问。这就排除了多个线程在同一时刻访问同一个共享变量而导致干扰与冲突的可能,即消除了竞态。

  2. CAS( Compare-and-Swap)指令:CAS指令实现原子性的方式与锁实现原子性的方式实质上是相同的,差别在于锁通常是在软件这一层次实现的,而CAS是直接在硬件(处理器和内存)这一层次实现的,它可以被看作“硬件锁”。

    注意:

  1.  从原子性的特性来看,让一个操作具有原子性就有消除竞态操作的可能性。因此我们可以将read-modify-write(读-改-写)和check-then-act(检测而后行动)操作装换为原子操作来消除竞态。

  2. 原子操作+原子操作 != 原子操作

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值