volatile能保证数据的可见性,但不能保证数据的原子性;而synchronized可以保证原子性,也能间接保证可见性,其可以将私有内存与公共内存的东西进行同步。
volatile解决的是多个线程之间的可见性,synchronized解决的是多个线程之间访问资源的同步性。
线程安全包括原子性与可见性两个方面,java的同步机制都是围绕着这两个方面确保线程安全的。
关键字volatile虽然增加了实例变量在多个线程之间的可见性,但它不具备同步性,那么就不具备原子性。
关键字volatile主要使用的场合是在多个线程中可以感知实例变量被更改了,并且可以获得最新的值使用,也就是说多线程读取共享变量时可以获得最新值使用。
对于JVM而言,volatile修饰的变量只能保证其从主内存read到线程内存是最新的,但是use与assign是多次出现的,且是非原子性的。可能出现主内存修改后,由于线程内存已经加载导致值不变进而出现脏读。
所以对于多个线程访问同一个实例变量还是需要加锁同步。
除了synchronized可以实现在i++操作时的同步外,AtomicInteger原子类也可以实现。
原子类型是不可分割的整体没有其他线程可以中断或检查正在原子操作的变量。
使用原子类的incrementAndGet()方法即可实现同步
原因在于:虽然每一次原子操作是不可打断的,但是如果有多次原子操作,且这些原子操作之间的调用顺序不是同步的,那么出来的结果也可能不是同步的。
实质:虽然最小操作是原子的,但是现在异步出现在上一级中,也就是说原子操作的执行顺序出现了异步的情况,最终也会导致结果出现异步,也就是说线程不安全。
synchronized不仅有使多个线程访问统一资源时顺序同步的功能,他也可以将线程的私有内存变量与公共内存变量同步的功能。
注:synchronized可以保证在同一时刻,只有一个线程可以执行某一个方法或某一个代码块,它包含两个特征:互斥性与可见性。
synchronized不仅仅可以解决一个线程看到对象处于不一致的状态(这里说的是可见性,指的是说可以保证对象在线程内存与公共内存保持一致。)
还可以保证进入同步方法或同步代码块的每一个线程,都能看到由同一个锁保护之前所有的修改效果(这里说的就是互斥性了,可以看到在自己进行加锁前(前提是当前线程抢到执行权),上一个线程锁在其锁期间完成的全部操作)。
学习多线程八个大字:“外练互斥、内修可见”。
看到这里是不是有点傻眼。。。好几小节的东西最好突然告诉你,其实你已经在使用的就是相对最好的。
基础的学习就是这样,一步一步才能踏实,然后才能够有自己的东西。只有看到不好的地方,才会想要做到更好的地方。
枯燥吗?还好,只是长时间高强度的话,脑袋却是有点懵,然后呢?还行吧,越大越发现学习的魅力,不得不说有点悲哀。
以自己的失败为鉴吧。