【Java基础】java-android面试Synchronized

简介: synchronized是Java的关键字,可用于同步实例方法、类方法(静态方法)、代码块。sychronized是非公平线程安全的,具有可见性、有序性,有原子性。

###  一、是什么

synchronized是Java的关键字,可用于同步实例方法、类方法(静态方法)、代码块。

sychronized是非公平线程安全的,具有可见性、有序性,有原子性。


### 二、实现原理

synchronized是依赖于 JVM来实现同步的。

synchronized同步代码块是通过加monitorenter和monitorexit指令实现的。

每个对象都有个监视器锁(monitor) ,当monitor被占用的时候就代表对象处于锁定状态,而monitorenter指令的作用就是获取monitor的所有权,monitorexit的作用是释放monitor的所有权。


可见性原理:

~~~

- 内存模型和happens-before规则。

- 这跟监视器(monitor)有关,即对同一个监视器的解锁,先于(happens-before)对该监视器的加锁

~~~

JMM关于synchronized的两条语义规定了:

- 线程加锁前:需要将工作内存清空,从而保证了工作区的变量副本都是从主存中获取的最新值。

- 线程解锁前;需要将工作内存的变量副本写回到主存中。


有序性跟原子性:

~~~

synchronized是给共享变量加锁,使用阻塞的同步机制

~~~


### 三、使用场景

同步实例方法、类方法(静态方法)、代码块。


### 四、优劣

- 效率低:锁的释放情况少,只有代码执行完毕或者异常结束才会释放锁;试图获取锁的时候不能设定超时,不能中断一个正在使用锁的线程,相对而言,Lock可以中断和设置超时

- 不够灵活:加锁和释放的时机单一,每个锁仅有一个单一的条件(某个对象),相对而言,读写锁更加灵活

- 无法知道是否成功获得锁,相对而言,Lock可以拿到状态


1. 提高程序的安全性:当多个线程同时访问共享资源时,synchronized 可以保证同一时间只有一个线程可以访问该资源,避免了多个线程同时修改共享资源而产生的数据不一致问题。

2. 提高程序的性能:由于 synchronized 代码块只有一个线程执行,因此可以提高程序的执行效率,减少线程之间的竞争,避免了不必要的数据拷贝和等待。

3. 简化代码:使用 synchronized 可以使代码更加简洁,减少了重复代码的出现,使代码更加易于维护和理解。



### 五、刷题

#### 1、 synchronized是非公平锁

~~~

synchronized底层使用mutext锁实现的,而mutext锁并不保证公平性,Synchronized 获取锁的行为是不公平的,并非是按照申请对象锁的先后时间分配锁的,每次对象锁被释放时,每个线程都有机会获得对象锁,这样有利于提高执行性能,但是也会造成线程饥饿现象。

~~~

#### 2、 Synchronized本质上是通过什么保证线程安全的?

~~~

synchronized关键字用于保证线程安全,其本质上是通过加锁和释放锁、可重入原理以及保证可见性原理来实现的。


1、加锁和释放锁的原理:

synchronized用于修饰方法或代码块,使得同一时间只有一个线程可以进入到临界区,并且在临界区执行代码块期间,其他线程必须等待该线程执行完毕后才能进入临界区。

加锁是在需要同步的代码块前加上锁,如果线程尝试进入临界区,则会阻塞等待该锁的持有者释放锁;

释放锁则是在不需要同步的代码块后释放锁,如果有其他线程进入了临界区,则会等待该线程执行完毕后才能继续执行。


2、可重入原理:

synchronized还可以保证同一个代码块不会被多个线程同时执行,从而避免了数据不一致的问题。


3、保证可见性原理:

synchronized还可以保证共享变量的可见性。如果多个线程同时访问共享变量,并且其中一个线程修改了该变量的值,那么其他线程需要等待修改该变量的线程执行完毕后才能访问该变量。

为了保证共享变量的可见性,synchronized会在访问共享变量的代码块前后加上锁,确保同一时间只有一个线程可以访问该变量。

~~~

#### 3、 Synchronized修饰的方法在抛出异常时,会释放锁吗?

~~~

synchronized修饰的方法,无论方法正常执行完毕还是抛出异常,都会释放锁

~~~

#### 4、 Synchronized和Lock的对比,如何选择?

~~~

synchronized和Lock都是用于线程同步的机制,它们的主要区别在于:

1、实现原理:synchronized是基于JVM底层的数据同步,而Lock是基于Java编写一个类,主要通过硬件依赖CPU指令实现数据同步。

2、释放锁的方式:synchronized是在同步代码块执行完毕或出现异常时,JVM会让线程释放锁,而Lock必须手工释放。

3、性能:在资源竞争不是很激烈的情况下,synchronized的性能要优于Lock,但是在资源竞争很激烈的情况下,Lock的性能能维持常态,ReentrantLock提供了多样化的同步,比如有时间限制的同步,可以被Interrupt的同步等。

4、可见性:synchronized可以保证共享变量的可见性,而Lock不保证可见性。


选择synchronized还是Lock主要取决于应用场景。对于对共享资源的同步和安全性要求较高的场景,建议使用synchronized;对于对性能要求较高的场景,可以使用Lock。如果在多个线程之间共享的资源不是很关键的情况下,可以使用Lock来代替synchronized。

~~~

#### 5、 多个线程等待同一个Synchronized锁的时候,JVM如何选择下一个获取锁的线程?

~~~

在多个线程等待同一个synchronized锁的情况下,JVM会按照以下顺序选择下一个获取锁的线程:

1、首先,JVM会检查当前正在获取锁的线程是否可达(即该线程是否已经访问过共享资源)。如果当前正在获取锁的线程可达,那么JVM会继续等待该线程执行完毕,然后再选择下一个线程。

2、如果当前正在获取锁的线程不可达,那么JVM会检查当前等待在锁上的线程数(即等待获取锁的线程数)。如果当前等待在锁上的线程数等于当前线程数,那么JVM会继续等待当前线程执行完毕,然后再选择下一个线程。

3、如果当前等待在锁上的线程数小于当前线程数,那么JVM会选择当前线程作为下一个获取锁的线程。这通常发生在一个非主线程中,当多个子线程都等待在一个


synchronized代码块中时,JVM会选择当前线程作为下一个获取锁的线程,因为非主线程没有访问共享资源的需求,它们只是在等待主线程执行完毕。


需要注意的是,在多个线程等待同一个synchronized锁的情况下,JVM会尽可能地让每个线程都有机会获取锁,但是在某些情况下,JVM可能会选择等待时间最长的线程来获取锁,从而保证锁的公平性。因此,在使用synchronized时,需要注意共享资源的访问模式和锁的使用方式,以便更好地控制线程同步和并发访问。

~~~

### 6、Synchronized使得同时只有一个线程可以执行,性能比较差,有什么提升的方法

~~~


Synchronized虽然可以保证同步代码块的执行效率,但是它的性能比较差,特别是在多个线程等待同一个锁的情况下。为了提升Synchronized的性能,可以考虑以下几种方法:


1、使用读写锁(ReentrantReadWriteLock):ReentrantReadWriteLock 比 synchronized 更加灵活,可以自由地控制锁的获取和释放。它提供了读锁和写锁两种模式,可以根据需求选择适当的模式,从而提高程序的性能。

2、避免使用Synchronized:在不需要同步的情况下,应该尽量避免使用 Synchronized。同时使用多个锁可能会导致死锁等问题,因此应该尽量避免在多个线程之间共享的代码块中使用 Synchronized。

3、使用更高级别的同步机制:如果应用程序需要更高级别的同步机制,可以考虑使用Java提供的并发容器,如 Collections.synchronizedList()、Collections.synchronizedSet() 和 Collections.synchronizedMap()。这些容器提供了更高级别的同步机制,可以更好地控制并发访问。

4、使用线程池:使用线程池可以更好地控制并发访问,避免多个线程同时修改共享资源而产生的数据不一致问题。线程池可以更好地控制线程数量和线程的执行时间,从而提高程序的性能。


总的来说,Synchronized虽然是一种常用的同步机制,但是在性能方面可能存在一些问题。通过使用更高级别的同步机制、避免使用Synchronized、使用线程池等方法,可以提高Synchronized的性能,从而更好地控制并发访问。

~~~

### 7、我想更加灵活的控制锁的释放和获取(现在释放锁和获取锁的时机都被规定死了),怎么办?

~~~

要更加灵活地控制锁的释放和获取,可以考虑以下两种方法:


1、使用适当的同步级别:如果应用程序需要更高级别的同步机制,可以考虑使用Java提供的并发容器,如 Collections.synchronizedList()、Collections.synchronizedSet() 和 Collections.synchronizedMap()。这些容器提供了更高级别的同步机制,可以更好地控制并发访问。

2、使用Java中的线程池:使用线程池可以更好地控制并发访问,避免多个线程同时修改共享资源而产生的数据不一致问题。线程池可以更好地控制线程数量和线程的执行时间,从而提高程序的性能。

使用适当的同步级别可以避免死锁等问题,同时可以灵活地控制锁的释放和获取。而使用线程池则可以更好地控制并发访问,提高程序的性能。

~~~

相关文章
|
7天前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
26 2
|
12天前
|
存储 算法 Java
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
本文详解自旋锁的概念、优缺点、使用场景及Java实现。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
大厂面试高频:什么是自旋锁?Java 实现自旋锁的原理?
|
12天前
|
存储 安全 Java
面试高频:Synchronized 原理,建议收藏备用 !
本文详解Synchronized原理,包括其作用、使用方式、底层实现及锁升级机制。关注【mikechen的互联网架构】,10年+BAT架构经验倾囊相授。
面试高频:Synchronized 原理,建议收藏备用 !
|
18天前
|
存储 缓存 Oracle
Java I/O流面试之道
NIO的出现在于提高IO的速度,它相比传统的输入/输出流速度更快。NIO通过管道Channel和缓冲器Buffer来处理数据,可以把管道当成一个矿藏,缓冲器就是矿藏里的卡车。程序通过管道里的缓冲器进行数据交互,而不直接处理数据。程序要么从缓冲器获取数据,要么输入数据到缓冲器。
Java I/O流面试之道
|
14天前
|
存储 缓存 Java
大厂面试必看!Java基本数据类型和包装类的那些坑
本文介绍了Java中的基本数据类型和包装类,包括整数类型、浮点数类型、字符类型和布尔类型。详细讲解了每种类型的特性和应用场景,并探讨了包装类的引入原因、装箱与拆箱机制以及缓存机制。最后总结了面试中常见的相关考点,帮助读者更好地理解和应对面试中的问题。
39 4
|
15天前
|
存储 Java 程序员
Java基础的灵魂——Object类方法详解(社招面试不踩坑)
本文介绍了Java中`Object`类的几个重要方法,包括`toString`、`equals`、`hashCode`、`finalize`、`clone`、`getClass`、`notify`和`wait`。这些方法是面试中的常考点,掌握它们有助于理解Java对象的行为和实现多线程编程。作者通过具体示例和应用场景,详细解析了每个方法的作用和重写技巧,帮助读者更好地应对面试和技术开发。
55 4
|
15天前
|
Java 大数据 API
14天Java基础学习——第1天:Java入门和环境搭建
本文介绍了Java的基础知识,包括Java的简介、历史和应用领域。详细讲解了如何安装JDK并配置环境变量,以及如何使用IntelliJ IDEA创建和运行Java项目。通过示例代码“HelloWorld.java”,展示了从编写到运行的全过程。适合初学者快速入门Java编程。
|
5天前
|
Java 开发者
Java多线程编程中的常见误区与最佳实践####
本文深入剖析了Java多线程编程中开发者常遇到的几个典型误区,如对`start()`与`run()`方法的混淆使用、忽视线程安全问题、错误处理未同步的共享变量等,并针对这些问题提出了具体的解决方案和最佳实践。通过实例代码对比,直观展示了正确与错误的实现方式,旨在帮助读者构建更加健壮、高效的多线程应用程序。 ####
|
4天前
|
安全 Java 开发者
Java 多线程并发控制:深入理解与实战应用
《Java多线程并发控制:深入理解与实战应用》一书详细解析了Java多线程编程的核心概念、并发控制技术及其实战技巧,适合Java开发者深入学习和实践参考。
|
4天前
|
Java 开发者
Java多线程编程的艺术与实践####
本文深入探讨了Java多线程编程的核心概念、应用场景及实践技巧。不同于传统的技术文档,本文以实战为导向,通过生动的实例和详尽的代码解析,引领读者领略多线程编程的魅力,掌握其在提升应用性能、优化资源利用方面的关键作用。无论你是Java初学者还是有一定经验的开发者,本文都将为你打开多线程编程的新视角。 ####

热门文章

最新文章

下一篇
无影云桌面