6.多线程锁 (公平锁和非公平锁,死锁,可重锁)

某一个时刻内,只能有唯一 一个线程去访问这些synchronized 方法
所有的静态同步方法用的也是同一把锁——类对象本身,这两把锁是两个不同的对象,所以静态同步方法与非静态同步方法之间是不会有竞态条件的但是一旦一个静态同步方法获取锁后,其他的静态同步方法都必须等待该方法释放锁后才能获取锁,而不管是同一个实例对象的静态同步方法之间,还是不同的实例对象的静态同步方法之间,只要它们同一个类的实例对象

    synchronized 锁的是方法,则是对象锁
    同个对象锁的机制要等待,不同对象锁的机制调用同一个不用等待
    加了static则为class锁而不是对象锁
通过具体的实例进行分析

 class Phone {
 
    public synchronized void sendSMS() throws Exception {
        //停留4秒
        TimeUnit.SECONDS.sleep(4);
        System.out.println("------sendSMS");
    }
    public synchronized void sendEmail() throws Exception {
        System.out.println("------sendEmail");
    }
    public void getHello() {
        System.out.println("------getHello");
    }
}
public class Lock_8 {
    public static void main(String[] args) throws Exception {
        Phone phone = new Phone();
        Phone phone2 = new Phone();
        new Thread(() -> {
            try {
                phone.sendSMS();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "AA").start();
        Thread.sleep(100);
        new Thread(() -> {
            try {
               // phone.sendEmail();
               // phone.getHello();
                phone2.sendEmail();
            } catch (Exception e) {
                e.printStackTrace();
            }
        }, "BB").start();
    }
}

 1 标准访问,先打印短信还是邮件
------sendSMS
------sendEmail
2 停4秒在短信方法内,先打印短信还是邮件
------sendSMS
------sendEmail
3 新增普通的hello方法,是先打短信还是hello
------getHello
------sendSMS
4 现在有两部手机,先打印短信还是邮件
------sendEmail
------sendSMS
5 两个静态同步方法,1部手机,先打印短信还是邮件
------sendSMS
------sendEmail
6 两个静态同步方法,2部手机,先打印短信还是邮件
------sendSMS
------sendEmail
7 1个静态同步方法,1个普通同步方法,1部手机,先打印短信还是邮件
------sendEmail
------sendSMS
8 1个静态同步方法,1个普通同步方法,2部手机,先打印短信还是邮件
------sendEmail
------sendSMS

总结:
1.- 同样的对象访问不同的同步锁,是按照顺序执行

    同样的对象访问同步锁与不同步锁,是先不同步锁执行
    不同对象访问不同同步锁,按照顺序执行

2.- 同一对象访问不同静态同步锁,按照顺序执行

    不同对象访问不同静态同步锁,按照顺序执行

3.- 同一对象访问一个静态同步锁,一个同步锁,先执行同步锁

    不同对象访问一个静态同步锁,一个同步锁,先执行同步锁
    即先出同步锁在出静态同步锁

 1、公平锁和非公平锁

公平锁:效率相对低 (但是cpu 的利用高了)
非公平锁:效率高,但是线程容易饿死(所有的工作,有一个线程完成)


通过查看源码
带有参数的ReentrantLock(true)为公平锁
ReentrantLock(false)为非公平锁
主要是调用NonfairSync()与FairSync()

2 可重入锁

synchronized和lock都是可重入锁

  • sychronized是隐式锁,不用手工上锁与解锁,而lock为显示锁,需要手工上锁与解锁
  • 可重入锁也叫递归锁

而且有了可重入锁之后,破解第一把之后就可以一直进入到内层结构

嵌套实现代码 他能进入下一个锁内

3 死锁

两个或以上的进程因为争夺资源而造成互相等待资源的现象称为死锁

在这里插入图片描述

产生死锁的原因:

  1. 系统资源不足
  2. 系统资源分配不当
  3. 进程运行顺序不当

我们有时候不知道是否是死锁  。那么怎么来验证呢? (电脑配置的有环境变量,在命令窗口)

  1.  jps 类似于linux中的 ps -ef 查看进程号
  2. jstack 自带的堆栈跟踪工具

具体死锁的操作代码实列
可理解背下来,大厂面试可考,死锁的简单案例

public class DeadLock {
 
    //创建两个对象
    static Object a = new Object();
    static Object b = new Object();
 
    public static void main(String[] args) {
        new Thread(()->{
            synchronized (a) {
                System.out.println(Thread.currentThread().getName()+" 持有锁a,试图获取锁b");
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (b) {
                    System.out.println(Thread.currentThread().getName()+" 获取锁b");
                }
            }
        },"A").start();
 
        new Thread(()->{
            synchronized (b) {
                System.out.println(Thread.currentThread().getName()+" 持有锁b,试图获取锁a");
                try {
                    TimeUnit.SECONDS.sleep(1);
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                synchronized (a) {
                    System.out.println(Thread.currentThread().getName()+" 获取锁a");
                }
            }
        },"B").start();
    }
}

 

posted @ 2022-03-12 19:26  随遇而安==  阅读(41)  评论(0编辑  收藏  举报