【java多线程】synchronized和volatile 一.synchronized 二、volatile 1.引出问题 三、volatile和synchronized的区别

1.synchronized使用的方法

  • 可以直接修饰代码块
synchronized (this) {
	//代码块
}
  • 调用可能出现并发问题的方法
synchronized (this) {
	method();
}
  • 修饰方法
public synchronized void method() {
	//...
}

2.注意

当synchronized修饰方法时:

  • 非静态方法中,synchronized锁当前对象:this
  • 静态方法中,synchronized锁的是当前类的字节码对象User.class

3.不要以字符串作为锁的对象

  • 有如下代码
String s1 = "hello";
String s2 = "hello";

void m1() {
    synchronized (s1) {
    }
}
void m2() {
    synchronized (s2) {
    }
}
  • 因为s1s2的创建都使用的是直接赋值,此时的hello会创建在常量池中,实际上s1s2都指向的是同一个对象,被s1、s2引用。
  • 所以,此时的synchronized (s1)synchronized (s2)实际上锁的都是同一个对象。
  • 因此,使用synchronized锁的时候最好不要锁字符串类型。
  • 如果非要锁字符串,那么使用new String ("hello")的方法来创建字符串,因为这样创建出来的字符串就是两个堆内存中的对象了。

4.synchronized锁的是什么?

  • synchronized锁的是堆内存中new出来的对象,而不是栈中的引用。
    【java多线程】synchronized和volatile
一.synchronized
二、volatile
1.引出问题
三、volatile和synchronized的区别

二、volatile

1.引出问题

【java多线程】synchronized和volatile
一.synchronized
二、volatile
1.引出问题
三、volatile和synchronized的区别

两个线程操作同一个主存数据时,会先将主存中的数据复制到自己的内存区域,将数据修改后,再写回主存。


两线程同时复制到自己内存后:

  • 线程1将数据修改a=1后,写回主存
  • main线程很忙,一直在进行while(true) 循环,没有时间再去主存中读取新的数据,所以main线程缓存中的数据还是a=0
  • 为了解决这个问题,就引出了volatile

2. volatile使用方法

  • 直接将volatile关键字加在要操作的数据上
private volatile int a = 0;

3.volatile原理

  • 线程1将数据修改后,会通知main线程:“你的数据已经过期了”
  • 此时main线程会从主存中重新读取新的数据
  • 这也就是volatile三个特性的-保证可见性
    【java多线程】synchronized和volatile
一.synchronized
二、volatile
1.引出问题
三、volatile和synchronized的区别

4.volatile三大特性

  • 保证可见性
  • 不保证原子性
  • 禁止指令重排

三、volatile和synchronized的区别

1.区别

  • volatile是轻量级的,synchronized是是重量级的
  • volatile保证内存可见性,而不保证原子性(解决此问题的办法:就是使用原子数据)
  • synchronized既保证内存可见性,也保证原子性

2.解决原子性问题–原子型数据类型

  • java.util.concurrent.atomic包下,有基本数据类型对应的原子型的数据类型,类似于基本数据类型的包装类型。
    【java多线程】synchronized和volatile
一.synchronized
二、volatile
1.引出问题
三、volatile和synchronized的区别

3.让对象类型数据具有原子型

  • 还是在java.util.concurrent.atomic包下,有一个类,可以使对象类型的数据具有原子性:AtomicReference
//创建两个对象
User zhangsan = new User("zhangsan");        
User sili = new User("sili");
//创建原子操作对象
AtomicReference<User> atomicReference = new AtomicReference<User>();
//比较并交换
boolean b = atomicReference.compareAndSet(zhangsan, sili);
System.out.println(b);