synchronized同步方法
关键字synchronized可用来保障原子性、可见性和有序性。
1)方法内变量私有:如果是方法内部的私有变量,则是线程安全的,是方法内部的变量是私有的造成的。
2)脏读写问题:但是多个线程共同访问的对象如果有多个实例变量,则运行的结果有可能出现交叉的情况。在读同一个对象的方法时,如果方法未声明synchronzied,则可能存在脏读的问题,是不同线程争抢实例的结果。
3)对象锁:synchronized创建的是对象锁,即访问不同的对象的时候,使用该方法还是同步的。但是如果访问同一个对象的不同的synchronized修饰的方法,则也是同步的。synchronzied会让这个对象使用synchronized修饰的方法都锁起来,即实现同步处理。只有共享资源的读写访问才需要同步块。
(同步方式容易造成死循环,可以通过调用同步块的方式解决,需要避免出现死锁带来的问题)
4)synchronized锁的可重入性:
对于获得某个对象的锁的线程,当对象锁还没有释放,还可以再次获取对象锁。(子类也可以通过“可重入锁”调用父类的同步方法)。即对象锁所在的方法可以再调用其他的对象锁方法。
5)当线程执行的代码出现异常时,其所持有的锁会自动释放
6)Synchronized同步方法不具有继承性,需要在子类中额外添加synchronized进行修饰
synchronized同步语句块
1)同步弊端:使用同步方法有弊端,会让另一个线程等待比较久的时间。
2)同步块作用范围:不在synchronized块中的方法是异步执行,在synchronized块中是同步执行的。使用synchronized(this)的方式进行处理。
3)同步块的阻塞性:当一个线程访问对象的synchronized(this)方法后,其他线程对同一个object中的所有其他调用该对象的synchronized(this)访问 将会被阻塞。
4)同步块锁定范围:synchronized(this)也是锁定当前对象的
5)同步调用的顺序性:多个线程调用同一个对象的不同名称的synchronized同步方法或者代码块时,调用的效果是按照顺序执行的。
6)synchronized(非this)和synchronized方法、synchronized(this)方法是异步的,可以提高运行效率。
使用了锁对象依然可能造成“脏读”的风险,因为不同线程进入代码块的顺序是不一样的,要注意方法的synchronized。
synchronized锁任意对象
支持将“任意对象”作为锁来实现同步功能,使用方式为synchronized(非this对象x)。不与其他非this同步方法争抢this锁,可以提高效率。(多个锁就是异步执行)
静态同步synchronized方法
synchronized关键字添加到static静态方法上是给Class类上锁,而非synchronized关键字加到非static静态方法上是给对象上锁(两个共存的情况下是异步调用的)。同步synchronized(class)方法和synchronized static方法的作用是一样的。
String类型的常量池特性
在synchronized(String)时,注意String会存放到常量池中,导致其他代码不能使用String作为锁对象。推荐使用Object
volatile关键字
当线程JVM设置为-server时,线程一直在线程的私有堆栈中取得变量。可能会造成和公共堆栈中的值不同。通过volatile关键字,强制从公共内存中读取变量的值。适用于多个线程感知到实例变量被更改了,多线程读取共享变量时可以获得最新值使用。(主要原因是私有内存和公有内存中的变量不同步)
Volatile关键字特点:
1)只保证了数据可见性,不保证数据的原子性
2)不会发生阻塞
3)Volatile不是线程同步的实现,性能比synchronized要好
4)关键字synchronized可以使多个线程访问同一个资源具有同步性,即将线程工作内存中的私有变量和公有内存的变量进行同步
AutomicInteger
I++ 操作的时候使用synchronized关键字实现同步外,还可以使用AtomicInteger原子类进行实现。原子类是不可分割的实体,没有其他线程可以中断或检查出处于原子操作中的变量。
代码重排序
CPU在执行代码时,会根据代码的执行时间进行优化。是为了追求更高的程序运行效率。重排序发生在没有依赖关系的时候。
Volatile关键字可以作为重排序的屏障,在之前或者之后的代码不能跨越屏障进行重排序