1.同步方法和同步代码块的区别
1) 语法不同,一个写在方法上,一个写在方法内部
2) 锁粒度不同,同步方法作用于整个方法,同步代码块作用于一段代码
3) 性能不同,同步方法低于同步块
4) 锁对象不同,同步方法是固定的,静态就是类.class,非静态的就是this
同步代码块可以指定锁对象
2.synchronized 锁机制的原理
通过监视器(monitor)完成
当对方法或一段代码上锁后,会启动监视器对这段代码监控,监视器中有计数器,当计数器为0时,允许线程进入,线程进入后,计数器加1,其它线程访问时,计数器不为0,不允许线程进入,线程执行完代码块后,计数器减1为0 ,监视器允许其它线程进入。
monitorenter
....
....
monitorexit
3.手写线程安全的单例模式
/**
* 懒汉式单例
*/
public class LazySingleton {
//2. 定义静态实例
private static LazySingleton instance = null;
//1. 私有构造方法
private LazySingleton(){
}
//3. 静态方法创建对象并返回
public static LazySingleton getInstance(){
//双检锁 DCL double check lock
//提升性能,不为空,就不执行同步块
if(instance == null) {
//同步代码块
synchronized (LazySingleton.class) {
//判断对象为空,再创建,整体执行
if (instance == null) {
instance = new LazySingleton();
}
}
}
return instance;
}
}
4. 什么是公平锁和非公平锁?
公平锁:等待锁时间长的线程,更容器获得锁
非公平锁:等待锁时间长和短的线程,获得锁几率相同
5.synchronized和同步锁的区别?
上锁:synchronized是自动上锁和解锁,同步锁是手动完成的
性能:同步锁的性能高于synchronized
使用:synchronized使用简单,功能单一,同步锁提供更多方法,使用灵活
6. 手写线程死锁的代码
有两个线程,两个锁,线程A持有锁B,需要锁A;线程B持有锁A,需要锁B;
提示:嵌套synchronized块
/**
* 线程死锁案例
*/
public class DeadLockDemo {
//两个锁对象
private Object lockA = new Object();
private Object lockB = new Object();
public void testA() throws InterruptedException {
synchronized (lockA){
System.out.println(Thread.currentThread().getName()+"持有锁A,需要锁B");
Thread.sleep(10);
synchronized (lockB){
System.out.println(Thread.currentThread().getName()+"持有锁A,B");
}
}
}
public void testB() throws InterruptedException {
synchronized (lockB){
System.out.println(Thread.currentThread().getName()+"持有锁B,需要锁A");
Thread.sleep(10);
synchronized (lockA){
System.out.println(Thread.currentThread().getName()+"持有锁A,B");
}
}
}
public static void main(String[] args) {
DeadLockDemo deadLockDemo = new DeadLockDemo();
new Thread(()->{
try {
deadLockDemo.testA();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
new Thread(()->{
try {
deadLockDemo.testB();
} catch (InterruptedException e) {
e.printStackTrace();
}
}).start();
}
}
7.synchronized和volatile的区别
修饰的对象:synchronized修改代码块或方法,volatile只能修饰变量
保证的特性:synchronized保证原子性、可见性;volatile不能保证原子性,保证可见性和有序性
性能:volatile是轻量级的线程同步方式,性能更高
8.讲讲悲观锁和乐观锁
悲观锁:比较悲观,认为线程同步问题会经常出现,倾向于给资源上锁
乐观锁:比较乐观,认为线程同步问题不会常出现,不给资源上锁,通过其它方式解决
版本号机制,对数据设置版本,每次修改后版本会更新,修改后将版本和前面版本进行比较,相同就提交,不同就不提交
CAS机制,CompareAndSwap
通过内存偏移量获得数据的原始值,通过原始值计算出预期的值,将预期的值和实际的值进行比较,相同就更新,否则就不更新进入循环等待状态,直到比较相等
如果线程的竞争比较激烈,应该使用悲观锁;
线程竞争不强的时候,使用乐观锁。