线程(2)——关键字volatile,synchronized

volatile

首先我们要了解java内存模型。所有实例域、静态域、数组元素都在堆内存中,堆内存在线程之间共享。java线程之间的通信由java内存模型(JMM)控制,JMM决定一个线程的写入何时对另一个线程可见。JMM定义了线程和主存之间的抽象关系:线程之间的共享变量存住在主存中,每个线程都有一行个私有的内存,本地内存存储了该线程以读/写共享变量的副本。
这里写图片描述
如图,线程之间要实现通信的话,必须经历以下两个步骤:

  1. 线程A把本地内存A中更新过的共享变量刷新到主存中去。
  2. 线程B到主存中去读取线程A之前已经更新过的共享变量。

然而volatile关键字保证了变量的可见性
对添加volatile关键字的变量,它的汇编码中会有一行加lock前缀。lock前缀的指令在多核处理器下引发了以下两个事件:

  1. 将当前处理器缓存行的内容写回到内存。
  2. 这个写回内存的操作会使其他CPU里缓存了该内存地址的数据无效。

synchronized

volatile并不能真正保证线程安全,它只能确保一个线程修改了数据后,其他线程能够看到这个改动。但两个线程同时修改一个数据时还是会发生冲突。要从根本上解决这个问题,我们就必学保证多个线程对变量进行操作时完成同步,也就是,当线程A在写入时,线程B不仅不能写,同时也不能读。

关键字synchronized的作用是实现线程间同步。它的工作是对同步的代码加锁,使得每一次只能有一个线程进入同步块,从而保证线程间的安全性。

  • 指定加锁对象:对给定对象加锁,进入同步代码前要获得给定的对象锁。
  • 直接作用于实例方法:相当于对当前实例加锁,进入同步代码前要获得当前实例的锁。
  • 直接作用于静态方法:相当于对当前类加锁,进入同步代码前要获得当前类的锁。
synchronized(instance){}//指定加锁对象
public synchronized void meth(){}//直接作用于实例方法,与上面加锁方式等价
(public static synchronized void meth(){}//这里是对类.class 加锁  而不是对类加锁)

举个例子

public class Demo{
String str="ddd";
//对str加锁
public void demo1(){
synchronized(str){}
}
//对this加锁
public synchronized void meth(){}
//对Demo.class加锁
public static synchronized void meth(){}
}

synchronized和volatile的

1)volatile本质是在告诉jvm当前变量在寄存器中的值是不确定的,需要从主存中读取,synchronized则是锁定当前变量,只有当前线程可以访问该变量,其他线程被阻塞住.
2)volatile仅能使用在变量级别,synchronized则可以使用在变量,方法。
3)volatile仅能实现变量的修改可见性,但不保证原子性。而synchronized则可以保证变量的修改可见性和原子性。
4)volatile不会造成线程的阻塞,而synchronized可能会造成线程的阻塞。
5)volatile解决的是变量在多个线程之间的可见性,而synchronized解决的是多个线程之间资源访问的同步性。

synchronized和重入锁(reentrantlock)的区别

  1. 与synchronized相比,重入锁有着显示的操作过程。开发人员必须手动指定何时加锁,何时释放锁。
  2. 对于synchronized来说,如果一个线程在等待锁,,那么结果只有两种情况,要么他获得这把锁继续执行,要么保持等待。而重入锁则提供另一种可能就是线程可以被中断。
  3. reentrantLock提供了可以超时的锁。
  4. 提供了乐观锁机制,trylock不会引起线程阻塞。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值