Synchronized 用过吗,其原理是什么???
Synchronized 有以下几个特点:
-
互斥性:Synchronized 保证同一时刻只有一个线程可以获取锁,并且只有该线程可以执行同步代码块中的代码。
-
可重入性:同一个线程可以多次获取同步锁而不会被阻塞,这样可以避免死锁的发生。
-
独占性: 如果一个线程获得了对象的锁,则其他线程必须等待该线程释放锁之后才能获取锁。
-
缺点:非公平锁 ,当锁被释放后,任何一个线程都有机会竞争得到锁,这样做的目的是提高效率,但缺点是可能产生线程饥饿现象。
Synchronized锁的升级过程
-
无锁
当一个对象被创建时,它最初是没有锁状态的,即处于无锁状态。
-
偏向锁
当第一个线程访问同步块时,如果该对象没有其他线程竞争,JVM会将对象头的Mark Word中的偏向线程ID设置为当前线程ID,并将Mark Word中的锁标志位改为偏向锁状态。这样,当前线程再次进入同步块时,无需再次获取锁,提高了效率。
-
轻量级锁(自旋锁)
偏向锁是轻量级锁的一种。
当有多个线程同时进入,来准备争夺这个共享资源时,此时会升级成自旋锁。新进入的线程会进入自旋等待状态。假如在自旋超过所设置的最大全数(不是固定的,假如是10),此时,锁会升级成为重量级锁
-
重量级锁(操作系统的内核态)
此时线程的处理将有操作系统来判断,看是否要对于该线程进行分配新的内存进行处理。
如果自旋锁超过了系统设定的阈值(默认10次,可以通过参数调整),或者在自旋期间有其他线程正在等待(已经进入了阻塞队列),那么锁会被升级为重量级锁。这时,JVM会创建一个互斥锁(Monitor),并将Mark Word中的锁标志位改为重量级锁状态。线程需要通过OS的调度器获取CPU时间片才能继续执行,这通常涉及从用户态到内核态的切换,性能开销较大。
总结
前三种锁都是在操作系统的用户态下执行的,重量级锁则是在操作系统的内核态执行。
一般来说,锁能在用户态下执行完成,都尽量不进入重量级锁,由操作系统进行处理。在保证线程安全的同时,尽可能减少锁带来的性能损耗。