线程系列(二)--同步

同步的原因

线程共享访问通信,会导致线程冲突和内存不一致问题,所以需要同步来解决这个问题。
1. 线程冲突(Thread Interference)
多个线程操作相同的数据,每个操作有多个步骤,那么可能一个操作还没完就开始执行另一个操作了,则肯定会导致数据错误。
2. 内存不一致错误(Memory consistency errors)
它的成因超出文本范围,我们只需要避免就行,那就是建立happen-before关系。

同步的几种方法

1.同步方法
给需要同步的方法加上synchonized关键字即可,如:

public synchronized void save(int n){num += n;}

这里得先介绍一下同步锁(Intrinsic lock):Java中每个对象都有一把关联的固有锁,一个对象的锁只能被一个线程拥有。也就是说当锁被一个线程拥有其他线程获取它就会受阻塞。则若想排他的、一致的访问对象的字段则必须获取该对象的固有锁,也就是同步锁。
在线程中一个对象调用同步方法时,就会自动获取该对象的同步锁,若该方法是静态方法那获取到的锁就是整个类的锁。
这里还需要注意的是它可能会有liveness问题。而且他不能同步构造方法,因为它将会在构造的时候锁住该对象,直到所有的构造器完成它们的工作,这个构造的过程对其它线程来说,通常是不可访问的。
同步是一种高开销的操作,同步方法的效率会比较低,所以又有了同步语句。

2.同步语句
给需要的语句块加上synchonized关键字,利于改善开发,代码如:

public void save(int n){
  synchronized(this){num += n;}
  }

3.重入同步
这里主要用到重入锁 ReentrantLock类,由java.util.concurrent包支持,后续会详细说明。现在只需要知道它与使用synchronized前两种方法具有相同的基本行为和语义,并且扩展了其能力就行。

注:关于Lock对象和synchronized关键字的选择: 
    a.最好两个都不用,使用一种java.util.concurrent包提供的机制,能够帮助用户处理所有与锁相关的代码。 
    b.如果synchronized关键字能满足用户的需求,就用synchronized,因为它能简化代码 
    c.如果需要更高级的功能,就用ReentrantLock类,此时要注意及时释放锁,否则会出现死锁,通常在finally代码释放锁 

4.使用特殊域变量volatile
a. volatile关键字为域变量的访问提供了一种免锁机制,该变量是所有线程立即可见的,使用volatile就相当于告诉虚拟机该域可能会被其他线程更新, 因此每次使用该域就要重新计算,而不是使用寄存器中的值,所以变量在各个线程是一致的。
b. volatile不会提供任何原子操作,它也不能用来修饰final类型的变量,但他能建立happen-before关系,保证可见性和有序性。
c. 禁止”指令重排序”,意思是执行volatile变量访问操作时,前面的所有语句是肯定全部执行完了的,而后面的语句肯定是都还没执行。
根据前面说的特点,那它有如下使用条件:
a.对变量的写操作不依赖于当前值,也就是保证原子性。
b.该变量是没有包含于其他变量的不定式中的。

5.使用局部变量
使用ThreadLocal管理变量,每一个使用该变量的线程都获得该变量的副本, 副本之间相互独立,这样每一个线程都可以随意修改自己的变量副本,而不会对其他线程产生影响。
在说handler的时候也讲到了ThreadLocal 这个类,简单说下它的常用方法:

ThreadLocal() : 创建一个线程本地变量 
get() : 返回此线程局部变量的当前线程副本中的值 
initialValue() : 返回此线程局部变量的当前线程的"初始值" 
set(T value) : 将此线程局部变量的当前线程副本中的值设置为value

线程协作

可以使用保护块(guarded block),比如消费者-生产者模式,消费者只有在生产者产生数据才能访问,生产者只能在消费者取走数据才能写。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值