Java synchronized 和 volatile 面试题

并发编程有三个重要的特性:原子性、有序性、可见性

volatile 无法保证原子性;synchronized 可以保证原子性。

synchronized 是以程序的串行化执行来保证顺序性,synchronized代码块中的代码指令也可以重排序;

volatile 禁止JVM编译器及处理器对volatile修饰的指令重新排序;

volatile 和 synchronized

volatile 和 synchronized 都用于保证多线程中数据的安全性

1、Java中为了解决并发编程中存在的原子性、可见性、有序性问题,提供了一些列和并发处理相关的关键字,如synchronized、volitaile、final、concurrent包等。
2、synchronized通过加锁的方式,使得其在需要原子性、可见性和有序性这三种特性时都可以作为其中一种解决方案,大部分并发控制操作都能使用synchronized来完成。

volatile和synchronized特点

首先需要理解线程安全的两个方面:执行控制和内存可见。
执行控制的目的是控制代码执行(顺序)及是否可以并发执行。
【内存可见】内存可见控制的是线程执行结果在内存中对其它线程的可见性。根据Java内存模型的实现,线程在具体执行时,会先拷贝主存数据到线程本地(CPU缓存),操作完成后再把结果从线程本地刷到主存。

volatile和synchronized的区别

volatile主要是保证内存的 可见性,即变量在寄存器中的内存是不确定的,需要从主存中读取。
synchronized主要是解决多个线程访问资源的同步性。

volatile仅能使用在变量级别;synchronized则可以使用在变量、方法、和类级别的。
volatile仅能实现变量的修改可见性,不能保证原子性;而synchronized则可以保证变量的修改可见性和原子性。
volatile不会造成线程的阻塞;synchronized可能会造成线程的阻塞。
volatile标记的变量不会被编译器优化;synchronized标记的变量可以被编译器优化。

.
.
.

synchronized

synchronized实现原理
synchronized核心组件
synchronized修饰类与修饰对象

修饰一个方法,被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
修饰一个类,其作用的范围是synchronized后面括号括起来的部分,作用主的对象是这个类的所有对象。

类锁修饰方法和代码块的效果和对象锁是一样的,因为类锁只是一个抽象出来的概念,只是为了区别静态方法的特点,因为静态方法是所有对象实例共用的,所以对应着synchronized修饰的静态方法的锁也是唯一的,所以抽象出来个类锁。其实这里的重点在下面这块代码,synchronized同时修饰静态和非静态方法。
上面代码synchronized同时修饰静态方法和实例方法,但是运行结果是交替进行的,这证明了类锁和对象锁是两个不一样的锁,控制着不同的区域,它们是互不干扰的。同样,线程获得对象锁的同时,也可以获得该类锁,即同时获得两个锁,这是允许的。

【补充】
java的内置锁:每个java对象都可以用做一个实现同步的锁,这些锁称为内置锁。线程进入同步代码块或方法的时候会自动获得该锁,在退出同步代码块或方法时会释放该锁。获得内置锁的唯一途径就是进入这个锁的保护的同步代码块或方法。
java内置锁是一个互斥锁,这就是意味着最多只有一个线程能够获得该锁,当线程A尝试去获得线程B持有的内置锁时,线程A必须等待或者阻塞,直到线程B释放这个锁,否则A线程将永远等待下去。

synchronized修饰的对象有几种

synchronized修饰的对象有几种:
a)修饰一个类:其作用的范围是synchronized后面括号括起来的部分,作用的对象是这个类的所有对象;
b)修饰一个方法:被修饰的方法称为同步方法,其作用的范围是整个方法,作用的对象是调用这个方法的对象;
修饰方法时锁定的是调用该方法的对象,即如果一个对象中有两个方法同时被synchronized,则同一个对象,调用这两个方法时,只能同时执行一个。
a)修饰一个静态的方法:其作用的范围是整个方法,作用的对象是这个类的所有对象;
b)修饰一个代码块:被修饰的代码块称为同步语句块,其作用范围是大括号{}括起来的代码块,作用的对象是调用这个代码块的对象;
synchronized(this)是对象锁,如果有多个对象就有相对应的多个锁。(修饰一个代码块)
synchronized(类的名.class)是全局锁,不管有几个对象就公用一把锁。(修饰一个类)

synchronized与Lock的区别

1.首先synchronized是java内置关键字,在jvm层面,Lock是个java类;
2.synchronized无法判断是否获取锁的状态,Lock可以判断是否获取到锁;
3.synchronized会自动释放锁(a 线程执行完同步代码会释放锁;b线程执行过程中发生异常会释放锁),Lock需在finally中手工释放锁(unlock()方法释放锁),否则容易造成线程死锁;
4.用synchronized关键字的两个线程1和线程2,如果当前线程1获得锁,线程2线程等待。如果线程1阻塞,线程2则会一直等待下去,而Lock锁就不一定会等待下去,如果尝试获取不到锁,线程可以不用一直等待就结束了;
5.synchronized的锁可重入、不可中断、非公平,而Lock锁可重入、可判断、可公平(两者皆可)
6.Lock锁适合大量同步的代码的同步问题,synchronized锁适合代码少量的同步问题。

synchronized方法和synchronized同步代码块的区别:

synchronized方法和synchronized同步代码块的区别:
synchronized同步代码块只是锁定了该代码块,代码块外面的代码还是可以被访问的。
synchronized方法是粗粒度的并发控制,某一个时刻只能有一个线程执行该synchronized方法。
synchronized同步代码块是细粒度的并发控制,只会将块中的代码同步,代码块之外的代码可以被其他线程同时访问;

静态方法和非静态方法上加锁的区别

1.静态方法加锁:类锁
Synchronized修饰静态方法,实际上是对该类对象加锁,俗称“类锁”
2.非静态方法加锁:对象锁
Synchronized修饰非静态方法,实际上是对调用该方法的对象加锁,俗称“对象锁”

静态方法和非静态方法上加锁的区别
https://blog.csdn.net/zzprongyi/article/details/91046236

你可能感兴趣的:(java,面试)