synchronized 关键字可以用来修饰的方法,类,代码块会被加锁,他能保证线程的互斥性;所谓互斥性就是线程1加了锁后,线程2就会被阻塞直到线程1释放锁;
synchronized 能够及时的刷新内存,保证了内存的可见性。 具体工作过程如下:
- ①获得互斥锁
- ②从主内存拷贝变量的最新副本到工作内存
- ③执行代码
- ④将更改后的共享变量的值刷新到主内存
- ⑤释放互斥锁
另外Synchronized允许一个线程针对同一把锁连续加锁多次(可重入),所以不会出现死锁这样的情况。
这是因为:可重入锁的内部维护了 “线程持有者” 和 “计数器” 这两个属性。
如果某个线程加锁的时候, 发现锁已经被人占用, 但是恰好占用的正是自己, 那么仍然可以继续获取到锁, 并让计数器自增。解锁的时候计数器递减为 0 的时候, 才真正释放锁 (才能被别的线程获取到)
在JMM中,每个线程都有自己独立的工作内存,即一组寄存器/cache高速缓冲区;在CPU和内存交互的时候,会先把内存中内容拷贝到工作内存,操作完之后在写回内存,这个过程非常容易出现数据不一致的情况,在编译器开启优化时特别严重
volatile 关键字用来修饰共享变量,保证共享变量的可见性,底层是在共享变量的两边增加内存屏障,禁止了指令重排;
- ① volatile能够保证内存的可见性,但是不能保证原子性。synchronized既能保证内存可见性,又能保证原子性。这是它们最本质的区别!
- ② volatile仅能使用在 变量 级别;synchronized则可以使用在变量、方法、和类级别的。
- ③ volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
- ④ volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化。