1、synchronized 为什么是非公平锁?非公平体现在哪些地方?
1)当持有锁的线程释放锁时,先将monitor锁对象的持有者 owner 属性赋值为 null,唤醒EntryList等待链表中的一个线程,但是线程尝试获取锁失败时,进入阻塞队列等待的先后顺序,和被唤醒、获取锁的顺序是不一致的,也就是说你先进入阻塞队列等待,当持有锁的线程释放锁时,不代表你就会先获取锁。
2)当持有锁的线程释放锁时,如果有其他线程刚好在尝试获取锁(例如自旋),则可以马上获取到锁。
2、什么是公平锁
公平锁:公平锁是指,当锁被其他线程持有后,剩下的线程尝试获取锁失败,会按照先后顺序进入阻塞队列/等待链表中排队、等待,当持有锁的线程释放锁时,阻塞队列中排在前面的线程会优先被唤醒、获取锁,这就称为公平锁。在Java中JUC包下的AQS就可以实现公平锁
非公平锁:由上面结论我们举反例可以知道,非公平锁就是,我不管你是否先来,谁先抢到锁谁就执行,sychronized就是一个非公平锁。
但为什么呢?其实很简单,在sychronized中有两个池的概念,一个是EntryList,一个是WaitSet,EntryList是一个单链表结构,当线程获取锁失败后,线程就会被封装称Entry对象然后加入到EntryList中。当某个持有锁线程调用wait()方法,线程就会释放锁然后加入到WaitSet中,当该线程被唤醒后会加入到EntryList中等待JVM调用。
但JVM并不会按照顺序去调用EntryList中的线程,而是随机调用,这也就导致了sychronized是一个非公平锁。
3、线程安全本质是什么,Java 如何保证线程安全?
答:线程安全是指在多线程环境中,多个线程对共享数据的访问和修改不会产生不一致或者不正确的结果。Java提供了多种机制来保证线程安全,其本质是通过控制并发访问共享资源的方式来实现的。
Java的线程安全是建立在原子性、可见性和有序性这三个基本特点上的。
- 原子性指的是一个操作不会被中断,要么全部完成,要么全部不完成;
- 可见性指的是多个线程访问同一个共享变量时,一个线程修改了变量,其他线程都可以立刻看到这个修改的结果;
- 有序性指的是程序的执行顺序按照代码的先后顺序执行。
Java提供了以下多种机制来保证线程安全:
- **synchronized关键字:**通过互斥锁来保证同一时刻只有一个线程获得锁,访问共享资源,其他线程需要进入阻塞队列,变成阻塞状态,等待锁的释放。synchronized关键字可以修饰方法、代码块或者静态方法。
- **ReentrantLock类:**ReentrantLock是可重入锁,与synchronized关键字相似。它提供了更多的灵活性和语义选择。线程获取锁时可以选择不同的等待策略,例如公平锁和非公平锁。
- **volatile关键字:**volatile关键字可以保证线程可以立即看到共享变量的更改,而不会看到变量的过期值。volatile关键字适用于单纯的读取数据的操作,不能保证多个操作之间的原子性。
- **AtomicInteger类:**AtomicInteger是一个原子类,提供了多个原子性方法,如getAndIncrement()、getAndDecrement()、getAndAdd()等。这些方法是原子性的,不需要使用synchronized关键字来保证线程安全。
通过使用以上这些机制,Java可以有效地保证线程安全。在开发多线程程序时,需要注意数据的访问和修改顺序,避免不正确的并发操作。同时,还应该避免死锁和饥饿等并发问题,以提高程序的性能和健壮性。
4、可重入锁
可重入锁 :字面意思是"可以重新进入的锁",可重入锁指的是允许同一个线程多次获取同一把锁。比如一个线程在执行一个带锁的方法,该方法中又调用了另一个需要相同锁的方法,则该线程可以直接执行调用的方法,而无需重新获得锁;
再比如一个线程调用递归函数,递归函数里有加锁的操作,在递归过程中这个锁不会阻塞自己,这个锁就是可重入锁(因为这个原因可重入锁也叫做递归锁)。
可重入锁可以避免死锁的出现:自己把自己阻塞住了、锁住了
synchronized锁和ReentrantLock锁都是可重入锁,两者都是同一个线程每进入一次,锁的计数器都自增1,所以要等到锁的计数器下降为0时才能释放锁。
线程在获取锁的时候,实际上就是获得一个监视器对象(monitor)
线程试图获取锁也就是获取monitor(monitor对象存在于每个Java对象的对象头中,synchronized 锁便是通过这种方式获取锁的,也是为什么Java中任意对象可以作为锁的原因)
在JDK1.6之后 synchronized锁引入了锁升级的过程 无锁、偏向锁、轻量级锁、重量级锁
,4种状态,4种状态会随着竞争的情况逐渐升级,升级的过程是不可逆的
在没有竞争时,synchronized 做了很多优化,如偏向锁、轻量级锁
注意: 加在成员方法上的synchronized关键字相当于 synchronized(this) 锁住的this对象;
加在静态方法上的synchronized关键字相当于synchronized(类.clss)锁住的当前类对象