文章目录
- 概述
- volatile
- synchornized
- volatile vs synchornized
- 总结
概述
提起并发编程,我们不得不说起 volatile 和 synchronized 这两个关键字,这两个关键字也是面试中常常被问到的,下面我们分别介绍一下这两个关键字以及二者的异同。首先需要理解线程安全的两个方面:执行控制和内存可见,执行控制的目的是控制代码执行(顺序)及是否可以并发执行,内存可见控制的是线程执行结果在内存中对其它线程的可见性。
volatile
首先,volatile 是变量修饰符,解决的是内存可见性问题。一般情况下线程在执行时,Java 中为了加快程序的运行效率,会先把主存数据拷贝到线程本地,操作完成后再把结果从线程本地缓存刷新到主存中,这样就会导致修改后放入变量结果同步到主存中需要一个过程,而此时另外的线程看到的还是修改之前的变量值,这样就会导致不一致。
为了解决上述多线程中内存可见的问题,引入了 volatile 关键字,那么它为什么可以解决内存可见性问题呢?volatile 它会使得所有对 volatile 变量的读写都会直接读写主存,而不是先读写线程本地缓存,这样就保证了变量的内存可见性。也就是说一旦某个线程修改了该被volatile修饰的变量,它会保证修改的值会立即被更新到主存,当有其他线程需要读取时,可以立即获取修改之后的值。
volatile 解决的是内存可见性的问题,会使得所有对volatile变量的读写都会直接刷到主存,即保证了变量的可见性。这样就能满足一些对变量可见性有要求而对读取顺序没有要求的需求。代码如下所示:
public class MyThread extends Thread { private volatile boolean isStop = false;public void run() {while (!isStop) {System.out.println("do something");}}public void setStop() {isStop = true;}
}
线程执行run()的时候我们需要在线程中不停的做一些事情,比如while循环,那么这时候该如何停止线程呢?如果线程做的事情不是耗时的,那么只需要使用一个标志即可。如果需要退出时,调用setStop()即可。这里就使用了关键字volatile,这个关键字的目的是如果修改了isStop的值,那么在while循环中可以立即读取到修改后的值。
synchornized
synchronized 可以修饰代码块或方法,既可以保证可见性,又解决了执行顺序问题。synchronized 解决的是执行控制的问题,它会阻止其它线程获取当前对象的监控锁,这样就使得当前对象中被 synchronized 关键字保护的代码块无法被其它线程访问,也就无法并发执行。
synchronized 是基于 monitor 实现的,通过 synchronized 或者 Lock 能保证同一时刻只有一个线程获取锁然后执行同步代码,并且在释放锁之前会将对变量的修改刷新到主存中。线程要么不执行(线程没有获取到对象锁),线程要么执行到底(线程获取到了对象锁),直到执行完释放锁。
volatile vs synchornized
- 相同点
volatile 和 synchronized 都保证了内存可见性。
- 不同点
- volatile 仅能使用在变量级别,synchronized 则可以使用在变量、方法、和类级别的。
- volatile 仅能实现变量的修改可见性,不能保证原子性,而 synchronized 则可以保证变量的修改可见性和原子性。
- volatile 不会造成线程的阻塞,而 synchronized 可能会造成线程的阻塞。
- volatile 标记的变量不会被编译器优化,而 synchronized 标记的变量可以被编译器优化。
总结
把今天最好的表现当作明天最新的起点…….~
投身于天地这熔炉,一个人可以被毁灭,但绝不会被打败!一旦决定了心中所想,便绝无动摇。迈向光明之路,注定荆棘丛生,自己选择的路,即使再荒谬、再艰难,跪着也要走下去!放弃,曾令人想要逃离,但绝境重生方为宿命。若结果并非所愿,那就在尘埃落定前奋力一搏!