面试题-13锁

首先来说下synchronize和Lock的区别

两者都是锁,用来控制并发冲突,区别在于Lock是个接口,提供的功能更加丰富,除了这个外,他们还有如下区别:
synchronize自动释放锁,而Lock必须手动释放,并且代码中出现异常会导致unlock代码不执行,所以Lock一般在Finally中释放,而synchronize释放锁是由JVM自动执行的。
Lock有共享锁的概念,所以可以设置读写锁提高效率,synchronize不能。(两者都可重入)
Lock可以让线程在获取锁的过程中响应中断,而synchronize不会,线程会一直等待下去。lock.lockInterruptibly()方法会优先响应中断,而不是像lock一样优先去获取锁。
Lock锁的是代码块,synchronize还能锁方法和类。

二、synconized实现原理

1、jvm基于进入和退出Monitor对象来实现方法同步和代码块同步。
方法级的同步是隐式,即无需通过字节码指令来控制的,它实现在方法调用和返回操作之中。JVM可以从方法常量池中的方法表结构(method_info
Structure) 中的 ACC_SYNCHRONIZED 访问标志区分一个方法是否同步方法。当方法调用时,调用指令将会 检查方法的
ACC_SYNCHRONIZED 访问标志是否被设置,如果设置了,执行线程将先持有monitor(虚拟机规范中用的是管程一词),
然后再执行方法,最后再方法完成(无论是正常完成还是非正常完成)时释放monitor。
2.代码块的同步是利用monitorenter和monitorexit这两个字节码指令。它们分别位于同步代码块的开始和结束位置。当jvm执行到monitorenter指令时,当前线程试图获取monitor对象的所有权,如果未加锁或者已经被当前线程所持有,就把锁的计数器+1;当执行monitorexit指令时,锁计数器-1;当锁计数器为0时,该锁就被释放了。如果获取monitor对象失败,该线程则会进入阻塞状态,直到其他线程释放锁。
各种锁的理解

1、公平锁、非公平锁 公平锁: 非常公平, 不能够插队,必须先来后到! 非公平锁:非常不公平,可以插队 (默认都是非公平) 2、可重入锁
可重入锁(递归锁)
在这里插入图片描述

Synchronized
package com.kuang.lock;
import javax.sound.midi.Soundbank;
// Synchronized
public class Demo01 {
public static void main(String[] args) {
Phone phone = new Phone();
new Thread(()->{
phone.sms();
},"A").start();
new Thread(()->{
phone.sms();
},"B").start();
}
}
class Phone{
public synchronized void sms(){
System.out.println(Thread.currentThread().getName() + "sms");
call(); // 这里也有锁
}
public synchronized void call(){
System.out.println(Thread.currentThread().getName() + "call");
}
}
Lock 版
package com.kuang.lock;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
public class Demo02 {
public static void main(String[] args) {
Phone2 phone = new Phone2();
new Thread(()->{
phone.sms();
},"A").start();
new Thread(()->{
phone.sms();
},"B").start();
}
}
class Phone2{
Lock lock = new ReentrantLock();
public void sms(){
lock.lock(); // 细节问题:lock.lock(); lock.unlock(); // lock 锁必须配对,否
则就会死在里面
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + "sms");
call(); // 这里也有锁
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
lock.unlock();
}
}
public void call(){
lock.lock();
try {
System.out.println(Thread.currentThread().getName() + "call");
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
}
}
}

3、自旋锁
spinlock
在这里插入图片描述

我们来自定义一个锁测试
测试

package com.kuang.lock;
import java.util.concurrent.atomic.AtomicReference;
* 自旋锁
*/
public class SpinlockDemo {
// int 0
// Thread null
AtomicReference<Thread> atomicReference = new AtomicReference<>();

// 加锁
public void myLock() {
Thread thread = Thread.currentThread();
System.out.println(Thread.currentThread().getName() + "==> mylock");
// 自旋锁
while (!atomicReference.compareAndSet(null, thread)) {
}
}

// 解锁
// 加锁
public void myUnLock() {
Thread thread = Thread.currentThread();
System.out.println(Thread.currentThread().getName() + "==> myUnlock");
atomicReference.compareAndSet(thread, null);
}
}
/**
* 锁
*/
public class asdf {
public static void main(String[] args) {
//如果用的是同一个锁 谁先获得锁 谁先用 其他线程只能等待获得锁才能向下走
Lock lock = new ReentrantLock();
// Lock lock1 = new ReentrantLock();
new Thread(()->{
lock.lock();
try {
TimeUnit.SECONDS.sleep(5);
System.out.println(Thread.currentThread().getName());
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
System.out.println("22");
}

},"t1").start();

new Thread(()->{
lock.lock();
try {
System.out.println(Thread.currentThread().getName());
} catch (Exception e) {
e.printStackTrace();
} finally {
lock.unlock();
System.out.println("33");
}

},"t2").start();
}
}
//运行结果
//t1
//t2
//33
//22

4、死锁
在这里插入图片描述

死锁测试,怎么排除死锁:
public class test1 {
public static void main(String[] args) {
String lockA = "A锁";
String lockB = "B锁";
new Thread(new MyThread(lockA,lockB)).start();
new Thread(new MyThread(lockB,lockA)).start();
}
}

class MyThread implements Runnable{
private String lockA;
private String lockB;

public MyThread(String lockA, String lockB) {
this.lockA = lockA;
this.lockB = lockB;
}

@Override
public void run() {
synchronized (lockA){
System.out.println(Thread.currentThread().getName()+lockA+"get->"+lockB);
try {
TimeUnit.SECONDS.sleep(2);
} catch (InterruptedException e) {
e.printStackTrace();
}
synchronized (lockB){
System.out.println(Thread.currentThread().getName()+lockB+"get->"+lockA);
}
}
}
}

解决问题 1、使用jps -l定位进程号

2、使用jstack +进程号 找到死锁问题

面试,工作中! 排查问题: 1、日志 9 2、堆栈 1

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zyf_fly66

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值