java锁相关

目录

目标

锁是访问资源的凭据,会消耗资源。
wait会破会Synchronized的原子性,因为会释放锁。
Synchronized从使用到原理。

JAVA中锁的概念

冲突:指数据的不一致性。
自旋锁:CAS操作机制,循环尝试等待。

乐观锁:认为不会有冲突竞争情况,会进行比对判断,不一致则失败。CAS机制。
悲观锁:认为一直会冲突竞争情况,每次只有一个线程可以拿到锁。

独享锁:在同一时刻只会有一个线程拿到,互斥。
共享锁:在同一时刻可以被多个线程获取。

可重入锁、不可重入锁:线程拿到锁后,如果没有释放,可以再次获取该锁,则为可重入,同一个线程可以重复加锁,否则为不可重入会进入阻塞状态。平常使用的锁基本都是可重入锁

公平锁、非公平锁:严格保证先来后到的顺序获取锁,则为公平锁,能插队则为非公平锁。
在这里插入图片描述

同步关键字synchronized

实例方法:作用于当前类实例。
静态方法:作用当前类对象。
锁消除:单个线程频繁使用synchronized进行加锁和解锁,则会进行jit优化,消除了锁。例如:StringBuffer。
锁粗化
在这里插入图片描述
在这里插入图片描述

synchronized底层原理

在这里插入图片描述

堆内存中的java对象

  1. java对象在内存中的布局
    在这里插入图片描述
    堆中存储的实例对象,只会存储实例字段的值和对象头相关的元数据信息。
    padding为补齐占位符。
    静态字段、方法、相关代码、静态方法等类的结构信息(类的所有信息都是元数据)都存储在方法区中。

  2. 对象头部
    Array length:存储的是数组对象的长度。
    Mark Word:实际上是对象当中,对象头部的一小段内存区域,存 储的值,主要包含5种属性。
    在这里插入图片描述
    在这里插入图片描述

    1. 如果对象未锁定,将状态拷贝到栈帧中的lock record中,通过CAS操作赋新值,即抢锁,修改成功后即抢锁成功,改为轻量级锁。
      在这里插入图片描述
    2. 多个线程通过CAS抢锁,失败则会自旋,尝试次数过多就会升级成重量级锁(用到了另外一个对象Object monitor)。
      在这里插入图片描述
      对象监视器(管程):每个对象都会有一个对象监视器,抢锁成功后owner指向对应的线程。entryList存储抢锁失败的线程,其中的线程状态为blocked状态,避免频繁消耗cpu资源,此时对象头中的mark word的值变成重量级锁,其引用指向Object monitor对象。
      objectmonitor在这里插入图片描述
      waitset:wait方法在synchronized方法中执行,进入到waitset中,线程状态为waiting,同时将锁释放。
      wait/notify在synchronized关键字中的情况。
  3. 偏向锁
    概念理解:减少CAS资源的损耗,只有一个线程抢锁,存储的线程如果是当前线程则不需要抢锁,直接获取该锁,则为偏向锁,若是其它线程,则升级为轻量级锁。
    在这里插入图片描述

    1. 锁的升级过程
      只有锁升级,没有锁降级。
      在这里插入图片描述
<think> 我们正在处理用户关于Java相关的笔试选择题的请求。根据引用[1]和引用[2]的内容,用户之前提供的引用都是关于Java面试题的选择题,但具体到的部分,引用中并没有直接给出。然而,我们可以根据Java的常见考点来创建一些典型的选择题。 Java相关的考点通常包括: - synchronized关键字 - ReentrantLock类 - 的类型(可重入、公平/非公平、读写等) - 死 - volatile关键字 - 的优化(如自旋消除、粗化等) 我们可以设计一些选择题,每个题目附上答案和解析。 下面提供几道常见的Java相关笔试选择题: --- ### **Java相关笔试选择题** #### 1. 关于`synchronized`关键字,以下说法错误的是() A. `synchronized`可以用于修饰实例方法 B. `synchronized`可以用于修饰静态方法 C. `synchronized`可以保证线程的可见性和原子性,但不能保证有序性 D. `synchronized`是可重入 <details> <summary>答案与解析</summary> 答案:C 解析: - A和B正确,`synchronized`可以修饰实例方法和静态方法,分别住当前实例对象和当前类的Class对象。 - C错误,`synchronized`可以保证原子性、可见性,同时也保证了有序性(因为一个线程在释放之前的所有操作对于随后获得的线程是可见的,且由于的互斥性,保证了有序性)。 - D正确,`synchronized`是可重入,同一个线程可以多次获取同一把。 因此,选项C是说法错误的。 </details> --- #### 2. 下列关于`ReentrantLock`和`synchronized`的区别,说法正确的是() A. `ReentrantLock`是关键字,而`synchronized`是类 B. `ReentrantLock`需要手动释放,而`synchronized`不需要 C. `ReentrantLock`只能是非公平,而`synchronized`可以是公平 D. `ReentrantLock`不能实现可重入,而`synchronized`可以 <details> <summary>答案与解析</summary> 答案:B 解析: - A错误,`ReentrantLock`是类,而`synchronized`是关键字。 - B正确,`ReentrantLock`需要显式调用`lock()`和`unlock()`方法,而`synchronized`在代码块执行完后会自动释放。 - C错误,`ReentrantLock`默认是非公平,但可以通过构造方法设置为公平;而`synchronized`是非公平。 - D错误,`ReentrantLock`和`synchronized`都是可重入。 因此,选项B正确。 </details> --- #### 3. 以下哪种情况不会引起死?() A. 线程A持有1并尝试获取2,线程B持有2并尝试获取1 B. 线程A持有1并尝试再次获取1 C. 线程A持有1并尝试获取2,同时线程B持有2并尝试获取3,线程C持有3并尝试获取1 D. 线程A循环等待线程B持有的,而线程B也在循环等待线程A持有的 <details> <summary>答案与解析</summary> 答案:B 解析: - 死产生的四个必要条件:互斥、请求与保持、不可剥夺、循环等待。 - A和D是典型的两个线程循环等待死;C是三个线程循环等待死。 - B是可重入的情况,同一个线程对同一个可以重入,不会发生死。 因此,选项B不会引起死。 </details> --- #### 4. 关于`volatile`关键字,以下说法正确的是() A. `volatile`能保证复合操作的原子性 B. `volatile`可以解决多线程环境下的所有并发问题 C. `volatile`可以保证变量的可见性和有序性 D. `volatile`变量的操作不需要加 <details> <summary>答案与解析</summary> 答案:C 解析: - A错误,`volatile`不能保证复合操作的原子性,比如`i++`操作。 - B错误,`volatile`不能解决所有并发问题,它只能保证可见性和有序性,不能保证原子性。 - C正确,`volatile`通过内存屏障保证可见性和禁止指令重排(有序性)。 - D正确,`volatile`变量操作不需要加,但要注意它不能保证原子性。 选项C和D都是正确的,但题目要求选择正确的是,并且D也是正确的,但C更全面地描述了`volatile`的特性。然而,本题是单选题,且通常C是更标准的答案(因为D虽然正确,但前提是原子操作,而复合操作则不行)。但严格来说,题目问的是“说法正确的是”,C和D都正确,但题目可能是单选题。因此,我们需要重新审视选项。 重新审视选项: - C:`volatile`可以保证变量的可见性和有序性(正确) - D:`volatile`变量的操作不需要加(正确,但是这里指的是对volatile变量的读写操作是原子的,所以单个读写操作不需要加,但复合操作还是需要) 由于题目是单选题,且C是`volatile`最核心的特性,而D虽然正确,但不够严谨(因为复合操作还是需要)。所以通常选择C。 但要注意:题目中并没有说单选题还是多选题,从格式上看是单选题(只有一个选项正确)。实际上,D也是正确的,但是题目要求选择正确的,而C是更本质的特性。我们再看其他选项,A和B错误,所以C和D正确,但题目可能是单选题,因此需要调整。 实际上,在Java中,`volatile`变量的读写操作都是原子的(包括long和double变量),所以单个读写操作不需要加。所以D正确。但是,题目要求选择正确的是,而C和D都正确,但我们只能选一个。因此,我们可能需要修改题目为单选题,所以选择最全面的选项。 然而,原题中并没有说明是多选题,所以按照单选题处理。实际上,很多笔试中,这道题的标准答案是C。因为D说法虽然正确,但不是`volatile`的完整特性,而C是它的两大特性(可见性和有序性)。同时,D的说法过于绝对,因为虽然不需要加,但并不能完全替代。 所以,我们选择C。 </details> --- #### 5. 下列哪个可以支持中断响应?() A. `synchronized` B. `ReentrantLock` C. 两者都支持 D. 两者都不支持 <details> <summary>答案与解析</summary> 答案:B 解析: - `synchronized`在等待的过程中无法被中断,只能一直等待。 - `ReentrantLock`提供了`lockInterruptibly()`方法,可以在等待的过程中响应中断。 因此,只有`ReentrantLock`支持中断响应,选项B正确。 </details> --- #### 6. 下面关于读写`ReentrantReadWriteLock`的描述,错误的是() A. 读是共享,写是独占 B. 读和写都支持重入 C. 写可以降级为读,读可以升级为写 D. 写被获取时,所有读的获取都必须等待 <details> <summary>答案与解析</summary> 答案:C 解析: - A正确,读写中,读是共享的,写是独占的。 - B正确,`ReentrantReadWriteLock`支持的重入。 - C错误,写可以降级为读(即先获取写,再获取读,然后释放写),但是读不能升级为写(因为可能会有多个读同时存在,升级为写需要独占,所以会导致死)。 - D正确,写被持有时,其他线程获取读和写都必须等待。 因此,选项C错误。 </details> --- #### 7. 下列哪种优化技术是通过避免线程在用户态和内核态之间切换来提高性能的?() A. 消除 B. 粗化 C. 自旋 D. 轻量级 <details> <summary>答案与解析</summary> 答案:C 解析: - 消除:编译器在运行时检测到不可能存在共享数据竞争的,将其消除。 - 粗化:将多个连续的操作合并为一个操作,减少请求次数。 - 自旋:当线程请求失败时,不立即阻塞,而是循环等待一段时间(自旋),避免用户态和内核态的切换开销。 - 轻量级:在无竞争的情况下使用CAS操作来避免使用重量级。 自旋通过自旋避免了线程切换(即用户态和内核态切换)的开销。所以答案是C。 </details> --- §§相关问题§§ 1. Java中`synchronized`和`ReentrantLock`在性能上有何差异? 2. 如何诊断和避免Java程序中的死? 3. `volatile`关键字和`synchronized`关键字在可见性上的区别是什么? </think> ### Java相关笔试选择题 以下是Java机制的常见笔试选择题(含答案与解析),结合Java并发编程核心知识点设计: --- #### 1. **关于`synchronized`关键字,说法正确的是()** A. `synchronized`可以修饰变量 B. `synchronized`静态方法住的是类实例对象 C. `synchronized`同步代码块支持可重入性 D. `synchronized`无法保证可见性和有序性 <details> <summary>答案与解析</summary> 答案:**C** 解析: - A错误:`synchronized`只能修饰方法或代码块,不能修饰变量。 - B错误:静态方法住的是类的`Class`对象,而非实例对象。 - C正确:同一线程可重复获取同一把(可重入特性)。 - D错误:`synchronized`通过`monitorenter/monitorexit`指令保证原子性、可见性和部分有序性[^1]。 </details> --- #### 2. **`ReentrantLock`与`synchronized`的主要区别是()** A. `ReentrantLock`是非阻塞 B. `ReentrantLock`必须手动释放 C. `synchronized`支持公平策略 D. `ReentrantLock`无法实现可重入 <details> <summary>答案与解析</summary> 答案:**B** 解析: - A错误:两者都是阻塞。 - B正确:`ReentrantLock`需显式调用`lock()`和`unlock()`;`synchronized`自动释放。 - C错误:`ReentrantLock`支持公平/非公平,`synchronized`仅非公平。 - D错误:`ReentrantLock`是可重入。 </details> --- #### 3. **以下可能引起死的代码场景是()** ```java // 线程1 synchronized (lockA) { synchronized (lockB) { /* ... */ } } // 线程2 synchronized (lockB) { synchronized (lockA) { /* ... */ } // 位置X } ``` A. 线程1先获得`lockA`,线程2先获得`lockB` B. 线程1和线程2同时执行位置X C. 线程1释放`lockB`后线程2再获取`lockA` D. 线程2使用`tryLock()`替代`synchronized` <details> <summary>答案与解析</summary> 答案:**A** 解析: - A正确:线程1持有`lockA`请求`lockB`,线程2持有`lockB`请求`lockA`,形成循环等待(死必要条件)。 - B错误:线程无法同时进入同步块。 - C错误:释放后不会死。 - D错误:`tryLock()`可避免死(尝试获取失败则放弃)。 </details> --- #### 4. **关于`volatile`关键字,说法错误的是()** A. 保证变量的可见性 B. 禁止指令重排序 C. 能替代`synchronized`实现原子操作 D. 适用于多线程读、单线程写的场景 <details> <summary>答案与解析</summary> 答案:**C** 解析: - A正确:强制线程从主内存读取最新值。 - B正确:通过内存屏障防止重排序。 - C错误:`volatile`不能保证复合操作(如`i++`)的原子性。 - D正确:典型用例如状态标志位[^2]。 </details> --- #### 5. **`ReadWriteLock`的特性是()** A. 写可被多个线程同时持有 B. 读释放前,写无法获取 C. 读与写互斥,读之间共享 D. 默认公平策略优于非公平策略 <details> <summary>答案与解析</summary> 答案:**C** 解析: - A错误:写是独占。 - B错误:写获取时,新读请求会被阻塞。 - C正确:读写互斥,读读共享(提高读密集型性能)。 - D错误:非公平策略吞吐量更高。 </details> ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值