JAVA高频面试题目集锦(3)

简介: JAVA高频面试题目集锦(3)

image.png


synchronized关键字

Syncchronized锁住了什么?

Synchronized锁的3种使用形式(使用场景):

Synchronized修饰普通同步方法:锁对象当前实例对象;

Synchronized修饰静态同步方法:锁对象是当前的类Class对象;

Synchronized修饰同步代码块:锁对象是Synchronized后面括号里配置的对象,这个对象可以是某个对象(xlock),也可以是某个类(Xlock.class);


Syncchronized的锁存在哪里?

对象是存放在堆内存中,对象大致可以分为三个部分,分别是对象头,实例变量,填充字节。


对象头主要是由MarkWord和Klass Point(类型指针组成)。

实例变量存储的是对象的属性信息,包括父类的属性信息,按照4字节对齐

填充字符,因为虚拟机要求对象字节必须是8字节的整数倍。

Syncchronized锁的对象存储在对象头的MarkWord中。每一个JAVA对象都会与一个监视器monitor关联,我们可以把它理解成为一把锁,当一个线程想要执行一段被synchronized修饰的同步方法或者代码块时,该线程得先获取到synchronized修饰的对象对应的monitor。monitorenter表示去获得一个对象监视器。monitorexit表示释放monitor监视器的所有权,使得其他被阻塞的线程可以尝试去获得这个监视器


锁分为四种类型:无锁状态、偏向锁状态、轻量级锁状态、重量级锁状态(级别从低到高)

除了 偏向锁可以转换为无状态锁,其他的锁都只能升不能降。


偏向所锁,轻量级锁都是乐观锁,重量级锁是悲观锁。 一个对象刚开始实例化的时候,没有任何线程来访问它的时候。它是可偏向的,意味着,它现在认为只可能有一个线程来访问它,所以当第一个线程来访问它的时候,它会偏向这个线程,此时,对象持有偏向锁。偏向第一个线程,这个线程在修改对象头成为偏向锁的时候使用CAS操作,并将对象头中的ThreadID改成自己的ID,之后再次访问这个对象时,只需要对比ID,不需要再使用CAS在进行操作。一旦有第二个线程访问这个对象,因为偏向锁不会主动释放,所以第二个线程可以看到对象时偏向状态,这时表明在这个对象上已经存在竞争了,检查原来持有该对象锁的线程是否依然存活,如果挂了,则可以将对象变为无锁状态,然后重新偏向新的线程,如果原来的线程依然存活,则马上执行那个线程的操作栈,检查该对象的使用情况,如果仍然需要持有偏向锁,则偏向锁升级为轻量级锁,(偏向锁就是这个时候升级为轻量级锁的)。如果不存在使用了,则可以将对象回复成无锁状态,然后重新偏向。 轻量级锁认为竞争存在,但是竞争的程度很轻,一般两个线程对于同一个锁的操作都会错开,或者说稍微等待一下(自旋),另一个线程就会释放锁。 但是当自旋超过一定的次数,或者一个线程在持有锁,一个在自旋,又有第三个来访时,轻量级锁膨胀为重量级锁,重量级锁使除了拥有锁的线程以外的线程都阻塞,防止CPU空转。


总结:偏向锁:只有一个线程进入临界区;

轻量级锁:多个线程交替进入临界区;

重量级锁:多个线程同时进入临界区。


volatile与 synchronized的区别


通过使用volatile关键字,是强制的从公共内存中读取变量的值, 是线程同步的轻量级实现, 所以volatile性能肯定比synchronized要好,并且 volatile只能修饰于变量,而synchronized可以修饰方法,以及代码块。


随着JDK新版本的发布,synchronized关键字在执行效率上得到很大提升,在开发中使用synchronized关键字的比率还是比较大的。


多线程访问volatile不会发生阻塞,而synchronized会出现阻塞。

volatile能保证数据的可见性,但不能保证原子性;而synchronized可以保证原子性,也可以间接保证可见性,因为它会将私有内存和公共内存中的数据做同步。


Lock与synchronized的区别

synchronized的缺陷

 在上面一篇文章中,我们了解到如果一个代码块被synchronized修饰了,当一个线程获取了对应的锁,并执行该代码块时,其他线程便只能一直等待,等待获取锁的线程释放锁,而这里获取锁的线程释放锁只会有两种情况:

 1)获取锁的线程执行完了该代码块,然后线程释放对锁的占有;

 2)线程执行发生异常,此时JVM会让线程自动释放锁。


那么如果这个获取锁的线程由于要等待IO或者其他原因(比如调用sleep方法)被阻塞了,但是又没有释放锁,其他线程便只能干巴巴地等待,试想一下,这多么影响程序执行效率。


 因此就需要有一种机制可以不让等待的线程一直无期限地等待下去(比如只等待一定的时间或者能够响应中断),通过Lock就可以办到。


 再举个例子:当有多个线程读写文件时,读操作和写操作会发生冲突现象,写操作和写操作会发生冲突现象,但是读操作和读操作不会发生冲突现象。


但是采用synchronized关键字来实现同步的话,就会导致一个问题:

 如果多个线程都只是进行读操作,所以当一个线程在进行读操作时,其他线程只能等待无法进行读操作。


 因此就需要一种机制来使得多个线程都只是进行读操作时,线程之间不会发生冲突,通过Lock就可以办到。


 另外,通过Lock可以知道线程有没有成功获取到锁。这个是synchronized无法办到的。


总结一下,也就是说Lock提供了比synchronized更多的功能。但是要注意以下几点:

 1)Lock不是Java语言内置的,synchronized是Java语言的关键字,因此是内置特性。Lock是一个类,通过这个类可以实现同步访问;


 2)Lock和synchronized有一点非常大的不同,采用synchronized不需要用户去手动释放锁,当synchronized方法或者synchronized代码块执行完之后,系统会自动让线程释放对锁的占用;而Lock则必须要用户去手动释放锁,如果没有主动释放锁,就有可能导致出现死锁现象。


Lock包含,上锁,获取锁,释放锁,


public interface Lock {
    void lock();   //就是用来获取锁。如果锁已被其他线程获取,则进行等待。
    void lockInterruptibly() throws InterruptedException;//当通过这个方法去获取锁时,如果线程正在等待获取锁,则这个线程能够响应中断,即中断线程的等待状态
    boolean tryLock();  //尝试获取锁
    boolean tryLock(long time, TimeUnit unit) throws InterruptedException;
    void unlock(); //释放锁
    Condition newCondition();
}
//lock 在使用中,强制上锁,不会被其他线程interrupt住;而trylock可以在规定的interval时间内,尝试获取锁,如果获取到,返回true,否则false。trylock随时可以被其他线程interrupt中断掉。


目录
相关文章
|
算法 Java
50道java集合面试题
50道 java 集合面试题
|
算法 Java
50道java基础面试题
50道java基础面试题
|
Java 数据库连接 数据库
Java 相关知识点总结含基础语法进阶技巧及面试重点知识
本文全面总结了Java核心知识点,涵盖基础语法、面向对象、集合框架、并发编程、网络编程及主流框架如Spring生态、MyBatis等,结合JVM原理与性能优化技巧,并通过一个学生信息管理系统的实战案例,帮助你快速掌握Java开发技能,适合Java学习与面试准备。
613 2
Java 相关知识点总结含基础语法进阶技巧及面试重点知识
|
缓存 Java 关系型数据库
Java 面试经验总结与最新 BAT 面试资料整理含核心考点的 Java 面试经验及最新 BAT 面试资料
本文汇总了Java面试经验与BAT等大厂常见面试考点,涵盖心态准备、简历优化、面试技巧及Java基础、多线程、JVM、数据库、框架等核心技术点,并附实际代码示例,助力高效备战Java面试。
625 0
|
缓存 Cloud Native Java
Java 面试微服务架构与云原生技术实操内容及核心考点梳理 Java 面试
本内容涵盖Java面试核心技术实操,包括微服务架构(Spring Cloud Alibaba)、响应式编程(WebFlux)、容器化(Docker+K8s)、函数式编程、多级缓存、分库分表、链路追踪(Skywalking)等大厂高频考点,助你系统提升面试能力。
1781 0
|
缓存 Java API
Java 面试实操指南与最新技术结合的实战攻略
本指南涵盖Java 17+新特性、Spring Boot 3微服务、响应式编程、容器化部署与数据缓存实操,结合代码案例解析高频面试技术点,助你掌握最新Java技术栈,提升实战能力,轻松应对Java中高级岗位面试。
795 0
JAVA高频面试题目集锦(6)
JAVA高频面试题目集锦(6)
405 0
JAVA高频面试题目集锦(6)
|
存储 安全 Java
JAVA高频面试题目集锦(5)
JAVA高频面试题目集锦(5)
406 1
JAVA高频面试题目集锦(5)