synchronized同步方法
多个线程对共享资源有写操作,则必须同步,如果只是读取操作,则不需要同步。
synchronized放在方法前面,是把对象作为锁
如果A线程先持有了Object锁,那么线程B调用改方法就得等到线程A结束释放锁。但B线程可以异步调用Object当中非synchronized的方法
解决脏读
当我们在修改数据的方法当中加上synchronized,但读取数据的方法当中没有加上synchronized的时候,就如同上面所写的B线程可以异步调用这个读取方法
多个线程调用一个业务对象中不同的同步方法的时候,是按照顺序同步的方式调用的。
synchronized同步语句块
锁非this对象具有一定的优点,如果一个类当中有很多synchronized方法,虽然能够实现同步,但影响运行效率,如果使用同步代码块锁非this对象,则synchronized代码中的程序与同步方法是异步的,因为是两把锁,不与其他锁this同步方法争抢this锁
volatile关键字
三个特性
- 可见性:B线程能马上看到A线程更改的数据
- 原子性:执行一组操作的时候不被打破
- 禁止代码重排序:代码重排序是由编译器和处理器为了优化执行速度而进行的一种优化手段(将不依赖的代码段进行重新排序),JIT即时编译器优化运行
synchronized关键字会把私有内存中的数据同步到公共内存同步,使私有内存中的数据和公共内存中的数据一致。
volatile关键字最致命的缺点是不支持运算原子性,也就是多个线程对volatile修饰的变量i执行i++/i--操作时候,这个操作还是会被分成三步,造成非现场安全问题。可以使用Atomic原子类进行i++操作实现原子性
- 32位JDK中的long、double数据类型的写操作为非原子性
violatile关键字提示线程每次从公共内存中去取变量,而不是从私有内存中去取,这样就保证了同步数据的可见性。
volatile关键字修饰的变量,和其无关的操作与这个变量的操作的相对位置不能变
A
B
C
v
D
E
A,B,C的操作可以重组,但不能到v之后,D,E的操作可以重组,但不能到v之前。这对synchronized关键字也适用
总结
- 当想要实现一个变量的值被更改,而其他线程能取到最新的值,就要对变量使用volatile
- 如果多个线程使用同一个对象中的同一个实例变量进行写操作,为了避免出现非线程安全问题,就要使用synchronized。